mirror of
https://github.com/strapi/strapi.git
synced 2025-08-15 04:08:04 +00:00
Merge pull request #5536 from strapi/fix/#4487/filteringDataManyWayError500
Fix deep filtering for manyWay
This commit is contained in:
commit
3e4c9d95d0
@ -79,31 +79,37 @@ const buildJoinsAndFilter = (qb, model, whereClauses) => {
|
|||||||
* @param {Object} destinationInfo - destination with which we are making a join
|
* @param {Object} destinationInfo - destination with which we are making a join
|
||||||
*/
|
*/
|
||||||
const buildJoin = (qb, assoc, originInfo, destinationInfo) => {
|
const buildJoin = (qb, assoc, originInfo, destinationInfo) => {
|
||||||
if (assoc.nature === 'manyToMany') {
|
if (['manyToMany', 'manyWay'].includes(assoc.nature)) {
|
||||||
const joinTableAlias = generateAlias(assoc.tableCollectionName);
|
const joinTableAlias = generateAlias(assoc.tableCollectionName);
|
||||||
|
|
||||||
|
let originColumnNameInJoinTable;
|
||||||
|
if (assoc.nature === 'manyToMany') {
|
||||||
|
originColumnNameInJoinTable = `${joinTableAlias}.${singular(
|
||||||
|
destinationInfo.model.attributes[assoc.via].attribute
|
||||||
|
)}_${destinationInfo.model.attributes[assoc.via].column}`;
|
||||||
|
} else if (assoc.nature === 'manyWay') {
|
||||||
|
originColumnNameInJoinTable = `${joinTableAlias}.${singular(
|
||||||
|
originInfo.model.collectionName
|
||||||
|
)}_${originInfo.model.primaryKey}`;
|
||||||
|
}
|
||||||
|
|
||||||
qb.leftJoin(
|
qb.leftJoin(
|
||||||
`${originInfo.model.databaseName}.${assoc.tableCollectionName} AS ${joinTableAlias}`,
|
`${originInfo.model.databaseName}.${assoc.tableCollectionName} AS ${joinTableAlias}`,
|
||||||
`${joinTableAlias}.${singular(
|
originColumnNameInJoinTable,
|
||||||
destinationInfo.model.attributes[assoc.via].attribute
|
|
||||||
)}_${destinationInfo.model.attributes[assoc.via].column}`,
|
|
||||||
`${originInfo.alias}.${originInfo.model.primaryKey}`
|
`${originInfo.alias}.${originInfo.model.primaryKey}`
|
||||||
);
|
);
|
||||||
|
|
||||||
qb.leftJoin(
|
qb.leftJoin(
|
||||||
`${destinationInfo.model.databaseName}.${destinationInfo.model.collectionName} AS ${destinationInfo.alias}`,
|
`${destinationInfo.model.databaseName}.${destinationInfo.model.collectionName} AS ${destinationInfo.alias}`,
|
||||||
`${joinTableAlias}.${singular(
|
`${joinTableAlias}.${singular(originInfo.model.attributes[assoc.alias].attribute)}_${
|
||||||
originInfo.model.attributes[assoc.alias].attribute
|
originInfo.model.attributes[assoc.alias].column
|
||||||
)}_${originInfo.model.attributes[assoc.alias].column}`,
|
}`,
|
||||||
`${destinationInfo.alias}.${destinationInfo.model.primaryKey}`
|
`${destinationInfo.alias}.${destinationInfo.model.primaryKey}`
|
||||||
);
|
);
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
const externalKey =
|
const externalKey =
|
||||||
assoc.type === 'collection'
|
assoc.type === 'collection'
|
||||||
? `${destinationInfo.alias}.${assoc.via ||
|
? `${destinationInfo.alias}.${assoc.via || destinationInfo.model.primaryKey}`
|
||||||
destinationInfo.model.primaryKey}`
|
|
||||||
: `${destinationInfo.alias}.${destinationInfo.model.primaryKey}`;
|
: `${destinationInfo.alias}.${destinationInfo.model.primaryKey}`;
|
||||||
|
|
||||||
const internalKey =
|
const internalKey =
|
||||||
@ -116,6 +122,7 @@ const buildJoinsAndFilter = (qb, model, whereClauses) => {
|
|||||||
externalKey,
|
externalKey,
|
||||||
internalKey
|
internalKey
|
||||||
);
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,9 +215,7 @@ const buildWhereClause = ({ qb, field, operator, value }) => {
|
|||||||
if (Array.isArray(value) && !['in', 'nin'].includes(operator)) {
|
if (Array.isArray(value) && !['in', 'nin'].includes(operator)) {
|
||||||
return qb.where(subQb => {
|
return qb.where(subQb => {
|
||||||
for (let val of value) {
|
for (let val of value) {
|
||||||
subQb.orWhere(q =>
|
subQb.orWhere(q => buildWhereClause({ qb: q, field, operator, value: val }));
|
||||||
buildWhereClause({ qb: q, field, operator, value: val })
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -258,7 +263,6 @@ const findModelByAssoc = assoc => {
|
|||||||
return models[assoc.collection || assoc.model];
|
return models[assoc.collection || assoc.model];
|
||||||
};
|
};
|
||||||
|
|
||||||
const findAssoc = (model, key) =>
|
const findAssoc = (model, key) => model.associations.find(assoc => assoc.alias === key);
|
||||||
model.associations.find(assoc => assoc.alias === key);
|
|
||||||
|
|
||||||
module.exports = buildQuery;
|
module.exports = buildQuery;
|
||||||
|
@ -236,6 +236,7 @@ module.exports = ({ models, target }, ctx) => {
|
|||||||
|
|
||||||
if (otherKey === foreignKey) {
|
if (otherKey === foreignKey) {
|
||||||
otherKey = `related_${otherKey}`;
|
otherKey = `related_${otherKey}`;
|
||||||
|
details.attribute = `related_${details.attribute}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadedModel[name] = function() {
|
loadedModel[name] = function() {
|
||||||
|
164
packages/strapi/__tests__/deepFiltering.test.e2e.js
Normal file
164
packages/strapi/__tests__/deepFiltering.test.e2e.js
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// Test an API with all the possible filed types and simple filterings (no deep filtering, no relations)
|
||||||
|
|
||||||
|
const { registerAndLogin } = require('../../../test/helpers/auth');
|
||||||
|
const createModelsUtils = require('../../../test/helpers/models');
|
||||||
|
const { createAuthRequest } = require('../../../test/helpers/request');
|
||||||
|
|
||||||
|
let rq;
|
||||||
|
let modelsUtils;
|
||||||
|
let data = {
|
||||||
|
paniniCards: [],
|
||||||
|
collectors: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const paniniCard = {
|
||||||
|
name: 'paniniCard',
|
||||||
|
kind: 'collectionType',
|
||||||
|
attributes: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const collector = {
|
||||||
|
name: 'collector',
|
||||||
|
kind: 'collectionType',
|
||||||
|
attributes: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
panini_cards: {
|
||||||
|
nature: 'manyWay',
|
||||||
|
target: 'application::panini-card.panini-card',
|
||||||
|
unique: false,
|
||||||
|
},
|
||||||
|
collector_friends: {
|
||||||
|
nature: 'manyWay',
|
||||||
|
target: '__self__',
|
||||||
|
unique: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const paniniCardFixtures = [
|
||||||
|
{
|
||||||
|
name: 'Hugo LLORIS',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Samuel UMTITI',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
async function createFixtures() {
|
||||||
|
for (let paniniCard of paniniCardFixtures) {
|
||||||
|
const res = await rq({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/panini-cards',
|
||||||
|
body: paniniCard,
|
||||||
|
});
|
||||||
|
|
||||||
|
data.paniniCards.push(res.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
const collector1Res = await rq({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/collectors',
|
||||||
|
body: {
|
||||||
|
name: 'Bernard',
|
||||||
|
panini_cards: [data.paniniCards[0].id, data.paniniCards[1].id],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
data.collectors.push(collector1Res.body);
|
||||||
|
|
||||||
|
const collector2Res = await rq({
|
||||||
|
method: 'POST',
|
||||||
|
url: '/collectors',
|
||||||
|
body: {
|
||||||
|
name: 'Isabelle',
|
||||||
|
panini_cards: [data.paniniCards[0].id],
|
||||||
|
collector_friends: [data.collectors[0].id],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
data.collectors.push(collector2Res.body);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteFixtures() {
|
||||||
|
for (let paniniCard of data.paniniCards) {
|
||||||
|
await rq({
|
||||||
|
method: 'DELETE',
|
||||||
|
url: `/panini-cards/${paniniCard.id}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (let collector of data.collectors) {
|
||||||
|
await rq({
|
||||||
|
method: 'DELETE',
|
||||||
|
url: `/collectors/${collector.id}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Deep Filtering API', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
const token = await registerAndLogin();
|
||||||
|
rq = createAuthRequest(token);
|
||||||
|
|
||||||
|
modelsUtils = createModelsUtils({ rq });
|
||||||
|
await modelsUtils.createContentTypes([paniniCard, collector]);
|
||||||
|
await createFixtures();
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
await deleteFixtures();
|
||||||
|
await modelsUtils.deleteContentTypes(['collector', 'panini-card']);
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
describe('Filter on a manyWay relation', () => {
|
||||||
|
test('Should return 2 results', async () => {
|
||||||
|
const res = await rq({
|
||||||
|
method: 'GET',
|
||||||
|
url: '/collectors',
|
||||||
|
qs: {
|
||||||
|
'panini_cards.name': data.paniniCards[0].name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(Array.isArray(res.body)).toBe(true);
|
||||||
|
expect(res.body.length).toBe(2);
|
||||||
|
expect(res.body[0]).toMatchObject(data.collectors[0]);
|
||||||
|
expect(res.body[1]).toMatchObject(data.collectors[1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should return 1 result', async () => {
|
||||||
|
const res = await rq({
|
||||||
|
method: 'GET',
|
||||||
|
url: '/collectors',
|
||||||
|
qs: {
|
||||||
|
'panini_cards.name': data.paniniCards[1].name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(Array.isArray(res.body)).toBe(true);
|
||||||
|
expect(res.body.length).toBe(1);
|
||||||
|
expect(res.body[0]).toMatchObject(data.collectors[0]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Filter on a self manyWay relation', () => {
|
||||||
|
test('Should return 1 result', async () => {
|
||||||
|
const res = await rq({
|
||||||
|
method: 'GET',
|
||||||
|
url: '/collectors',
|
||||||
|
qs: {
|
||||||
|
'collector_friends.name': data.collectors[0].name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('res', JSON.stringify(res.body, null, 2));
|
||||||
|
|
||||||
|
expect(Array.isArray(res.body)).toBe(true);
|
||||||
|
expect(res.body.length).toBe(1);
|
||||||
|
expect(res.body[0]).toMatchObject(data.collectors[1]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user