Skip to content

Commit

Permalink
fix(core): Fix EntityHydrator missing nested relations
Browse files Browse the repository at this point in the history
Fixes #1161
  • Loading branch information
michaelbromley committed Oct 19, 2021
1 parent 11fcc42 commit fbda3dd
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 6 deletions.
22 changes: 19 additions & 3 deletions packages/core/e2e/entity-hydrator.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* tslint:disable:no-non-null-assertion */
import { mergeConfig, Product } from '@vendure/core';
import { mergeConfig, Product, ProductVariant } from '@vendure/core';
import { createTestEnvironment } from '@vendure/testing';
import gql from 'graphql-tag';
import path from 'path';
Expand Down Expand Up @@ -122,7 +122,7 @@ describe('Entity hydration', () => {
// https://github.com/vendure-ecommerce/vendure/issues/1153
it('correctly handles empty array relations', async () => {
// Product T_5 has no asset defined
const { hydrateProductAsset } = await adminClient.query<HydrateProductAssetQuery>(
const { hydrateProductAsset } = await adminClient.query<{ hydrateProductAsset: Product }>(
GET_HYDRATED_PRODUCT_ASSET,
{
id: 'T_5',
Expand All @@ -131,14 +131,25 @@ describe('Entity hydration', () => {

expect(hydrateProductAsset.assets).toEqual([]);
});

// https://github.com/vendure-ecommerce/vendure/issues/1161
it('correctly expands missing relations', async () => {
// Product T_5 has no asset defined
const { hydrateProductVariant } = await adminClient.query<{ hydrateProductVariant: ProductVariant }>(
GET_HYDRATED_VARIANT,
{ id: 'T_1' },
);

expect(hydrateProductVariant.product.id).toBe('T_1');
expect(hydrateProductVariant.product.facetValues.map(fv => fv.id).sort()).toEqual(['T_1', 'T_2']);
});
});

function getVariantWithName(product: Product, name: string) {
return product.variants.find(v => v.name === name)!;
}

type HydrateProductQuery = { hydrateProduct: Product };
type HydrateProductAssetQuery = { hydrateProductAsset: Product };

const GET_HYDRATED_PRODUCT = gql`
query GetHydratedProduct($id: ID!) {
Expand All @@ -150,3 +161,8 @@ const GET_HYDRATED_PRODUCT_ASSET = gql`
hydrateProductAsset(id: $id)
}
`;
const GET_HYDRATED_VARIANT = gql`
query GetHydratedVariant($id: ID!) {
hydrateProductVariant(id: $id)
}
`;
18 changes: 17 additions & 1 deletion packages/core/e2e/fixtures/test-plugins/hydration-test-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ID,
PluginCommonModule,
Product,
ProductVariantService,
RequestContext,
TransactionalConnection,
VendurePlugin,
Expand All @@ -13,7 +14,11 @@ import gql from 'graphql-tag';

@Resolver()
export class TestAdminPluginResolver {
constructor(private connection: TransactionalConnection, private entityHydrator: EntityHydrator) {}
constructor(
private connection: TransactionalConnection,
private productVariantService: ProductVariantService,
private entityHydrator: EntityHydrator,
) {}

@Query()
async hydrateProduct(@Ctx() ctx: RequestContext, @Args() args: { id: ID }) {
Expand Down Expand Up @@ -45,6 +50,16 @@ export class TestAdminPluginResolver {
});
return product;
}

// Test case for https://github.com/vendure-ecommerce/vendure/issues/1161
@Query()
async hydrateProductVariant(@Ctx() ctx: RequestContext, @Args() args: { id: ID }) {
const [variant] = await this.productVariantService.findByIds(ctx, [args.id]);
await this.entityHydrator.hydrate(ctx, variant, {
relations: ['product.facetValues.facet'],
});
return variant;
}
}

@VendurePlugin({
Expand All @@ -55,6 +70,7 @@ export class TestAdminPluginResolver {
extend type Query {
hydrateProduct(id: ID!): JSON
hydrateProductAsset(id: ID!): JSON
hydrateProductVariant(id: ID!): JSON
}
`,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,11 @@ export class EntityHydrator {
for (const relation of options.relations.slice().sort()) {
if (typeof relation === 'string') {
const parts = relation.split('.');
let entity: any = target;
let entity: Record<string, any> | undefined = target;
const path = [];
for (const part of parts) {
path.push(part);
if (entity[part]) {
if (entity && entity[part]) {
entity = Array.isArray(entity[part]) ? entity[part][0] : entity[part];
} else {
const allParts = path.reduce((result, p, i) => {
Expand All @@ -158,6 +158,7 @@ export class EntityHydrator {
}
}, [] as string[]);
missingRelations.push(...allParts);
entity = undefined;
}
}
}
Expand Down

0 comments on commit fbda3dd

Please sign in to comment.