diff --git a/packages/core/e2e/fixtures/test-plugins/list-query-plugin.ts b/packages/core/e2e/fixtures/test-plugins/list-query-plugin.ts index 36d4d29d93..b780f3dea6 100644 --- a/packages/core/e2e/fixtures/test-plugins/list-query-plugin.ts +++ b/packages/core/e2e/fixtures/test-plugins/list-query-plugin.ts @@ -39,9 +39,25 @@ export class CustomFieldRelationTestEntity extends VendureEntity { parent: Relation; } +@Entity() +export class CustomFieldOtherRelationTestEntity extends VendureEntity { + constructor(input: Partial) { + super(input); + } + + @Column() + data: string; + + @ManyToOne(() => TestEntity) + parent: Relation; +} + class TestEntityCustomFields { @OneToMany(() => CustomFieldRelationTestEntity, child => child.parent) relation: Relation; + + @OneToMany(() => CustomFieldOtherRelationTestEntity, child => child.parent) + otherRelation: Relation; } @Entity() @@ -143,7 +159,7 @@ export class TestEntityTranslation extends VendureEntity implements Translation< @ManyToOne(type => TestEntity, base => base.translations) base: TestEntity; - customFields: {}; + customFields: never; } @Entity() @@ -171,7 +187,12 @@ export class ListQueryResolver { return this.listQueryBuilder .build(TestEntity, args.options, { ctx, - relations: ['orderRelation', 'orderRelation.customer', 'customFields.relation'], + relations: [ + 'orderRelation', + 'orderRelation.customer', + 'customFields.relation', + 'customFields.otherRelation', + ], customPropertyMap: { customerLastName: 'orderRelation.customer.lastName', }, @@ -222,8 +243,14 @@ const apiExtensions = gql` data: String! } + type CustomFieldOtherRelationTestEntity implements Node { + id: ID! + data: String! + } + type TestEntityCustomFields { relation: [CustomFieldRelationTestEntity!]! + otherRelation: [CustomFieldOtherRelationTestEntity!]! } type TestEntity implements Node { @@ -272,7 +299,13 @@ const apiExtensions = gql` @VendurePlugin({ imports: [PluginCommonModule], - entities: [TestEntity, TestEntityPrice, TestEntityTranslation, CustomFieldRelationTestEntity], + entities: [ + TestEntity, + TestEntityPrice, + TestEntityTranslation, + CustomFieldRelationTestEntity, + CustomFieldOtherRelationTestEntity, + ], adminApiExtensions: { schema: apiExtensions, resolvers: [ListQueryResolver], @@ -409,6 +442,12 @@ export class ListQueryPlugin implements OnApplicationBootstrap { data: nestedContent.data, }), ); + await this.connection.getRepository(CustomFieldOtherRelationTestEntity).save( + new CustomFieldOtherRelationTestEntity({ + parent: testEntity, + data: nestedContent.data, + }), + ); } } } diff --git a/packages/core/e2e/list-query-builder.e2e-spec.ts b/packages/core/e2e/list-query-builder.e2e-spec.ts index 84b47bdf96..b4b228f7ef 100644 --- a/packages/core/e2e/list-query-builder.e2e-spec.ts +++ b/packages/core/e2e/list-query-builder.e2e-spec.ts @@ -1268,6 +1268,27 @@ describe('ListQueryBuilder', () => { }, ]); }); + + it('should resolve multiple relations in customFields successfully', async () => { + const { testEntities } = await shopClient.query(GET_LIST_WITH_MULTIPLE_CUSTOM_FIELD_RELATION, { + options: { + filter: { + label: { eq: 'A' }, + }, + }, + }); + + expect(testEntities.items).toEqual([ + { + id: 'T_1', + label: 'A', + customFields: { + relation: [{ id: 'T_1', data: 'A' }], + otherRelation: [{ id: 'T_1', data: 'A' }], + }, + }, + ]); + }); }); }); @@ -1351,3 +1372,24 @@ const GET_LIST_WITH_CUSTOM_FIELD_RELATION = gql` } } `; + +const GET_LIST_WITH_MULTIPLE_CUSTOM_FIELD_RELATION = gql` + query GetTestWithMultipleCustomFieldRelation($options: TestEntityListOptions) { + testEntities(options: $options) { + items { + id + label + customFields { + relation { + id + data + } + otherRelation { + id + data + } + } + } + } + } +`; diff --git a/packages/core/src/service/helpers/list-query-builder/list-query-builder.ts b/packages/core/src/service/helpers/list-query-builder/list-query-builder.ts index d060c1a68b..c44ba88e67 100644 --- a/packages/core/src/service/helpers/list-query-builder/list-query-builder.ts +++ b/packages/core/src/service/helpers/list-query-builder/list-query-builder.ts @@ -493,14 +493,21 @@ export class ListQueryBuilder implements OnApplicationBootstrap { loadEagerRelations: true, } as FindManyOptions) .then(results => - results.map(r => ({ relation: relationPaths[0] as keyof T, entity: r })), + results.map(r => ({ + relations: relationPaths[0].startsWith('customFields.') + ? relationPaths + : [relationPaths[0]], + entity: r, + })), ); }), ).then(all => all.flat()); for (const entry of entitiesIdsWithRelations) { const finalEntity = entityMap.get(entry.entity.id); - if (finalEntity) { - this.assignDeep(entry.relation, entry.entity, finalEntity); + for (const relation of entry.relations) { + if (finalEntity) { + this.assignDeep(relation, entry.entity, finalEntity); + } } } return Array.from(entityMap.values());