fix xToOne relations + finish e2e tests

This commit is contained in:
Pierre Noël 2022-10-10 14:25:44 +02:00
parent 8f73a1d761
commit bd82249ab6
2 changed files with 278 additions and 13 deletions

View File

@ -7,8 +7,15 @@ const { createAuthRequest } = require('../../../../../../test/helpers/request');
const builder = createTestBuilder();
let strapi;
let rq;
const data = {
categories: [],
categoriesdp: {
published: [],
draft: [],
},
};
const product = {
const productModel = {
displayName: 'Product',
singularName: 'product',
pluralName: 'products',
@ -25,6 +32,12 @@ const product = {
target: 'api::categorydp.categorydp',
targetAttribute: 'product',
},
onecategorydp: {
type: 'relation',
relation: 'oneToOne',
target: 'api::categorydp.categorydp',
targetAttribute: 'oneproduct',
},
categories: {
type: 'relation',
relation: 'oneToMany',
@ -38,6 +51,7 @@ const product = {
comporep: {
component: 'default.compo',
type: 'component',
repeatable: true,
},
dz: {
components: ['default.compo'],
@ -46,7 +60,7 @@ const product = {
},
};
const categoryDP = {
const categoryDPModel = {
displayName: 'Category Draft & Publish',
singularName: 'categorydp',
pluralName: 'categoriesdp',
@ -54,41 +68,41 @@ const categoryDP = {
attributes: {
name: {
type: 'string',
unique: true,
},
},
};
const category = {
const categoryModel = {
displayName: 'Category',
singularName: 'category',
pluralName: 'categories',
attributes: {
name: {
type: 'string',
unique: true,
},
},
};
const compo = {
const compoModel = {
displayName: 'compo',
attributes: {
name: {
type: 'string',
required: true,
},
categoriesdp: {
type: 'relation',
relation: 'oneToMany',
target: 'api::categorydp.categorydp',
targetAttribute: 'product',
},
categories: {
type: 'relation',
relation: 'oneToMany',
target: 'api::category.category',
targetAttribute: 'product',
},
onecategorydp: {
type: 'relation',
relation: 'oneToOne',
target: 'api::categorydp.categorydp',
},
},
};
@ -96,13 +110,45 @@ const compo = {
describe('CM API - Basic', () => {
beforeAll(async () => {
await builder
.addContentTypes([categoryDP, category])
.addComponent(compo)
.addContentTypes([product])
.addContentTypes([categoryDPModel, categoryModel])
.addComponent(compoModel)
.addContentTypes([productModel])
.build();
strapi = await createStrapiInstance();
rq = await createAuthRequest({ strapi });
const { body: category } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::category.category',
body: { name: 'Food' },
});
data.categories.push(category);
const { body: categoryPublished } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::categorydp.categorydp',
body: { name: 'Food' },
});
await rq({
method: 'POST',
url: `/content-manager/collection-types/api::categorydp.categorydp/${categoryPublished.id}/actions/publish`,
});
data.categoriesdp.published.push(categoryPublished);
const { body: categoryDraft1 } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::categorydp.categorydp',
body: { name: 'Food' },
});
data.categoriesdp.draft.push(categoryDraft1);
const { body: categoryDraft2 } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::categorydp.categorydp',
body: { name: 'Food' },
});
data.categoriesdp.draft.push(categoryDraft2);
});
afterAll(async () => {
@ -111,11 +157,40 @@ describe('CM API - Basic', () => {
});
test('Return 0 when no relations are set', async () => {
const { body: product } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::product.product',
body: { name: 'Pizza' },
});
const { body } = await rq({
method: 'GET',
url: `/content-manager/collection-types/api::product.product/${product.id}/actions/numberOfDraftRelations`,
});
expect(body.data).toBe(0);
});
test('Return 0 when only relations without d&p are set', async () => {
const { body: product } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::product.product',
body: {
name: 'Pizza',
onecategorydp: data.categories[0].id,
categories: [data.categories[0].id],
compo: {
onecategorydp: data.categories[0].id,
categories: [data.categories[0].id],
},
comporep: [{ categories: [data.categories[0].id], onecategorydp: data.categories[0].id }],
dz: [
{
__component: 'default.compo',
categories: [data.categories[0].id],
onecategorydp: data.categories[0].id,
},
],
},
});
@ -126,4 +201,159 @@ describe('CM API - Basic', () => {
expect(body.data).toBe(0);
});
test('Return 0 when relations without d&p are set & published relations only', async () => {
const categoryId = data.categories[0].id;
const publishedId = data.categoriesdp.published[0].id;
const { body: product } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::product.product',
body: {
name: 'Pizza',
onecategorydp: publishedId,
categories: [categoryId],
categoriesdp: [publishedId],
compo: {
onecategorydp: publishedId,
categories: [categoryId],
categoriesdp: [publishedId],
},
comporep: [
{ onecategorydp: publishedId, categories: [categoryId], categoriesdp: [publishedId] },
],
dz: [
{
__component: 'default.compo',
onecategorydp: publishedId,
categories: [categoryId],
categoriesdp: [publishedId],
},
],
},
});
const { body } = await rq({
method: 'GET',
url: `/content-manager/collection-types/api::product.product/${product.id}/actions/numberOfDraftRelations`,
});
expect(body.data).toBe(0);
});
test('Return 8 when there are 8 drafts (1 xToOne & 1 xToMany on ct, compo, comporep, dz)', async () => {
const categoryId = data.categories[0].id;
const draftId = data.categoriesdp.draft[0].id;
const { body: product } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::product.product',
body: {
name: 'Pizza',
onecategorydp: draftId,
categories: [categoryId],
categoriesdp: [draftId],
compo: {
onecategorydp: draftId,
categories: [categoryId],
categoriesdp: [draftId],
},
comporep: [{ onecategorydp: draftId, categories: [categoryId], categoriesdp: [draftId] }],
dz: [
{
__component: 'default.compo',
onecategorydp: draftId,
categories: [categoryId],
categoriesdp: [draftId],
},
],
},
});
const { body } = await rq({
method: 'GET',
url: `/content-manager/collection-types/api::product.product/${product.id}/actions/numberOfDraftRelations`,
});
expect(body.data).toBe(8);
});
test('Return 8 when there are 8 drafts (1 xToOne & 1/2 xToMany on ct, compo, comporep, dz)', async () => {
const categoryId = data.categories[0].id;
const draftId = data.categoriesdp.draft[0].id;
const { body: product } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::product.product',
body: {
name: 'Pizza',
onecategorydp: draftId,
categories: [categoryId],
categoriesdp: [draftId, categoryId],
compo: {
onecategorydp: draftId,
categories: [categoryId],
categoriesdp: [draftId, categoryId],
},
comporep: [
{ onecategorydp: draftId, categories: [categoryId], categoriesdp: [draftId, categoryId] },
],
dz: [
{
onecategorydp: draftId,
__component: 'default.compo',
categories: [categoryId],
categoriesdp: [draftId, categoryId],
},
],
},
});
const { body } = await rq({
method: 'GET',
url: `/content-manager/collection-types/api::product.product/${product.id}/actions/numberOfDraftRelations`,
});
expect(body.data).toBe(8);
});
test('Return 12 when there are 12 drafts (1 xToOne & 2 xToMany on ct, compo, comporep, dz)', async () => {
const categoryId = data.categories[0].id;
const draft1Id = data.categoriesdp.draft[0].id;
const draft2Id = data.categoriesdp.draft[1].id;
const { body: product } = await rq({
method: 'POST',
url: '/content-manager/collection-types/api::product.product',
body: {
name: 'Pizza',
onecategorydp: draft1Id,
categories: [categoryId],
categoriesdp: [draft1Id, draft2Id],
compo: {
onecategorydp: draft1Id,
categories: [categoryId],
categoriesdp: [draft1Id, draft2Id],
},
comporep: [
{ onecategorydp: draft1Id, categories: [categoryId], categoriesdp: [draft1Id, draft2Id] },
],
dz: [
{
onecategorydp: draft1Id,
__component: 'default.compo',
categories: [categoryId],
categoriesdp: [draft1Id, draft2Id],
},
],
},
});
const { body } = await rq({
method: 'GET',
url: `/content-manager/collection-types/api::product.product/${product.id}/actions/numberOfDraftRelations`,
});
expect(body.data).toBe(12);
});
});

View File

@ -11,7 +11,7 @@ const { fromRow } = require('../transform');
* @returns
*/
const XtoOne = async (input, ctx) => {
const { attribute, attributeName, results, populateValue, targetMeta } = input;
const { attribute, attributeName, results, populateValue, targetMeta, isCount } = input;
const { db, qb } = ctx;
const fromTargetRow = (rowOrRows) => fromRow(targetMeta, rowOrRows);
@ -61,6 +61,41 @@ const XtoOne = async (input, ctx) => {
results.map((r) => r[referencedColumnName]).filter((value) => !_.isNil(value))
);
if (isCount) {
if (_.isEmpty(referencedValues)) {
results.forEach((result) => {
result[attributeName] = { count: 0 };
});
return;
}
const rows = await qb
.init(populateValue)
.join({
alias,
referencedTable: joinTable.name,
referencedColumn: joinTable.inverseJoinColumn.name,
rootColumn: joinTable.inverseJoinColumn.referencedColumn,
rootTable: qb.alias,
on: joinTable.on,
})
.select([joinColAlias, qb.raw('count(*) AS count')])
.where({ [joinColAlias]: referencedValues })
.groupBy(joinColAlias)
.execute({ mapResults: false });
const map = rows.reduce((map, row) => {
map[row[joinColumnName]] = { count: Number(row.count) };
return map;
}, {});
results.forEach((result) => {
result[attributeName] = map[result[referencedColumnName]] || { count: 0 };
});
return;
}
if (_.isEmpty(referencedValues)) {
results.forEach((result) => {
result[attributeName] = null;