mirror of
https://github.com/strapi/strapi.git
synced 2025-09-04 22:32:57 +00:00
fix xToOne relations + finish e2e tests
This commit is contained in:
parent
8f73a1d761
commit
bd82249ab6
@ -7,8 +7,15 @@ const { createAuthRequest } = require('../../../../../../test/helpers/request');
|
|||||||
const builder = createTestBuilder();
|
const builder = createTestBuilder();
|
||||||
let strapi;
|
let strapi;
|
||||||
let rq;
|
let rq;
|
||||||
|
const data = {
|
||||||
|
categories: [],
|
||||||
|
categoriesdp: {
|
||||||
|
published: [],
|
||||||
|
draft: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const product = {
|
const productModel = {
|
||||||
displayName: 'Product',
|
displayName: 'Product',
|
||||||
singularName: 'product',
|
singularName: 'product',
|
||||||
pluralName: 'products',
|
pluralName: 'products',
|
||||||
@ -25,6 +32,12 @@ const product = {
|
|||||||
target: 'api::categorydp.categorydp',
|
target: 'api::categorydp.categorydp',
|
||||||
targetAttribute: 'product',
|
targetAttribute: 'product',
|
||||||
},
|
},
|
||||||
|
onecategorydp: {
|
||||||
|
type: 'relation',
|
||||||
|
relation: 'oneToOne',
|
||||||
|
target: 'api::categorydp.categorydp',
|
||||||
|
targetAttribute: 'oneproduct',
|
||||||
|
},
|
||||||
categories: {
|
categories: {
|
||||||
type: 'relation',
|
type: 'relation',
|
||||||
relation: 'oneToMany',
|
relation: 'oneToMany',
|
||||||
@ -38,6 +51,7 @@ const product = {
|
|||||||
comporep: {
|
comporep: {
|
||||||
component: 'default.compo',
|
component: 'default.compo',
|
||||||
type: 'component',
|
type: 'component',
|
||||||
|
repeatable: true,
|
||||||
},
|
},
|
||||||
dz: {
|
dz: {
|
||||||
components: ['default.compo'],
|
components: ['default.compo'],
|
||||||
@ -46,7 +60,7 @@ const product = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const categoryDP = {
|
const categoryDPModel = {
|
||||||
displayName: 'Category Draft & Publish',
|
displayName: 'Category Draft & Publish',
|
||||||
singularName: 'categorydp',
|
singularName: 'categorydp',
|
||||||
pluralName: 'categoriesdp',
|
pluralName: 'categoriesdp',
|
||||||
@ -54,41 +68,41 @@ const categoryDP = {
|
|||||||
attributes: {
|
attributes: {
|
||||||
name: {
|
name: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
unique: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const category = {
|
const categoryModel = {
|
||||||
displayName: 'Category',
|
displayName: 'Category',
|
||||||
singularName: 'category',
|
singularName: 'category',
|
||||||
pluralName: 'categories',
|
pluralName: 'categories',
|
||||||
attributes: {
|
attributes: {
|
||||||
name: {
|
name: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
unique: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const compo = {
|
const compoModel = {
|
||||||
displayName: 'compo',
|
displayName: 'compo',
|
||||||
attributes: {
|
attributes: {
|
||||||
name: {
|
name: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
required: true,
|
|
||||||
},
|
},
|
||||||
categoriesdp: {
|
categoriesdp: {
|
||||||
type: 'relation',
|
type: 'relation',
|
||||||
relation: 'oneToMany',
|
relation: 'oneToMany',
|
||||||
target: 'api::categorydp.categorydp',
|
target: 'api::categorydp.categorydp',
|
||||||
targetAttribute: 'product',
|
|
||||||
},
|
},
|
||||||
categories: {
|
categories: {
|
||||||
type: 'relation',
|
type: 'relation',
|
||||||
relation: 'oneToMany',
|
relation: 'oneToMany',
|
||||||
target: 'api::category.category',
|
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', () => {
|
describe('CM API - Basic', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await builder
|
await builder
|
||||||
.addContentTypes([categoryDP, category])
|
.addContentTypes([categoryDPModel, categoryModel])
|
||||||
.addComponent(compo)
|
.addComponent(compoModel)
|
||||||
.addContentTypes([product])
|
.addContentTypes([productModel])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
strapi = await createStrapiInstance();
|
strapi = await createStrapiInstance();
|
||||||
rq = await createAuthRequest({ strapi });
|
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 () => {
|
afterAll(async () => {
|
||||||
@ -111,11 +157,40 @@ describe('CM API - Basic', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Return 0 when no relations are set', async () => {
|
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({
|
const { body: product } = await rq({
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: '/content-manager/collection-types/api::product.product',
|
url: '/content-manager/collection-types/api::product.product',
|
||||||
body: {
|
body: {
|
||||||
name: 'Pizza',
|
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);
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -11,7 +11,7 @@ const { fromRow } = require('../transform');
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const XtoOne = async (input, ctx) => {
|
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 { db, qb } = ctx;
|
||||||
|
|
||||||
const fromTargetRow = (rowOrRows) => fromRow(targetMeta, rowOrRows);
|
const fromTargetRow = (rowOrRows) => fromRow(targetMeta, rowOrRows);
|
||||||
@ -61,6 +61,41 @@ const XtoOne = async (input, ctx) => {
|
|||||||
results.map((r) => r[referencedColumnName]).filter((value) => !_.isNil(value))
|
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)) {
|
if (_.isEmpty(referencedValues)) {
|
||||||
results.forEach((result) => {
|
results.forEach((result) => {
|
||||||
result[attributeName] = null;
|
result[attributeName] = null;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user