Skip to content

Commit

Permalink
fix(core): Handle nullable relations in EntityHydrator (#2683)
Browse files Browse the repository at this point in the history
Fixes #2682
  • Loading branch information
jnugh authored Feb 20, 2024
1 parent 2075d6d commit 4e1f408
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 1 deletion.
56 changes: 55 additions & 1 deletion packages/core/e2e/entity-hydrator.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import {
Asset,
ChannelService,
EntityHydrator,
mergeConfig,
Expand All @@ -21,7 +22,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { initialData } from '../../../e2e-common/e2e-initial-data';
import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';

import { HydrationTestPlugin } from './fixtures/test-plugins/hydration-test-plugin';
import { AdditionalConfig, HydrationTestPlugin } from './fixtures/test-plugins/hydration-test-plugin';
import { UpdateChannelMutation, UpdateChannelMutationVariables } from './graphql/generated-e2e-admin-types';
import {
AddItemToOrderDocument,
Expand Down Expand Up @@ -50,6 +51,14 @@ describe('Entity hydration', () => {
customerCount: 2,
});
await adminClient.asSuperAdmin();

const connection = server.app.get(TransactionalConnection).rawConnection;
const asset = await connection.getRepository(Asset).findOne({ where: {} });
await connection.getRepository(AdditionalConfig).save(
new AdditionalConfig({
backgroundImage: asset,
}),
);
}, TEST_SETUP_TIMEOUT_MS);

afterAll(async () => {
Expand Down Expand Up @@ -240,6 +249,45 @@ describe('Entity hydration', () => {
expect(hydrateChannel.customFields.thumb.id).toBe('T_2');
});

it('hydrates a nested custom field', async () => {
await adminClient.query<UpdateChannelMutation, UpdateChannelMutationVariables>(UPDATE_CHANNEL, {
input: {
id: 'T_1',
customFields: {
additionalConfigId: 'T_1',
},
},
});

const { hydrateChannelWithNestedRelation } = await adminClient.query<{
hydrateChannelWithNestedRelation: any;
}>(GET_HYDRATED_CHANNEL_NESTED, {
id: 'T_1',
});

expect(hydrateChannelWithNestedRelation.customFields.additionalConfig).toBeDefined();
});

// https://github.com/vendure-ecommerce/vendure/issues/2682
it('hydrates a nested custom field where the first level is null', async () => {
await adminClient.query<UpdateChannelMutation, UpdateChannelMutationVariables>(UPDATE_CHANNEL, {
input: {
id: 'T_1',
customFields: {
additionalConfigId: null,
},
},
});

const { hydrateChannelWithNestedRelation } = await adminClient.query<{
hydrateChannelWithNestedRelation: any;
}>(GET_HYDRATED_CHANNEL_NESTED, {
id: 'T_1',
});

expect(hydrateChannelWithNestedRelation.customFields.additionalConfig).toBeNull();
});

// https://github.com/vendure-ecommerce/vendure/issues/2013
describe('hydration of OrderLine ProductVariantPrices', () => {
let order: Order | undefined;
Expand Down Expand Up @@ -378,3 +426,9 @@ const GET_HYDRATED_CHANNEL = gql`
hydrateChannel(id: $id)
}
`;

const GET_HYDRATED_CHANNEL_NESTED = gql`
query GetHydratedChannelNested($id: ID!) {
hydrateChannelWithNestedRelation(id: $id)
}
`;
35 changes: 35 additions & 0 deletions packages/core/e2e/fixtures/test-plugins/hydration-test-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Asset,
ChannelService,
Ctx,
DeepPartial,
EntityHydrator,
ID,
LanguageCode,
Expand All @@ -14,9 +15,11 @@ import {
ProductVariantService,
RequestContext,
TransactionalConnection,
VendureEntity,
VendurePlugin,
} from '@vendure/core';
import gql from 'graphql-tag';
import { Entity, ManyToOne } from 'typeorm';

@Resolver()
export class TestAdminPluginResolver {
Expand Down Expand Up @@ -125,10 +128,34 @@ export class TestAdminPluginResolver {
});
return channel;
}

@Query()
async hydrateChannelWithNestedRelation(@Ctx() ctx: RequestContext, @Args() args: { id: ID }) {
const channel = await this.channelService.findOne(ctx, args.id);
await this.entityHydrator.hydrate(ctx, channel!, {
relations: [
'customFields.thumb',
'customFields.additionalConfig',
'customFields.additionalConfig.backgroundImage',
],
});
return channel;
}
}

@Entity()
export class AdditionalConfig extends VendureEntity {
constructor(input?: DeepPartial<AdditionalConfig>) {
super(input);
}

@ManyToOne(() => Asset, { onDelete: 'SET NULL', nullable: true })
backgroundImage: Asset;
}

@VendurePlugin({
imports: [PluginCommonModule],
entities: [AdditionalConfig],
adminApiExtensions: {
resolvers: [TestAdminPluginResolver],
schema: gql`
Expand All @@ -140,11 +167,19 @@ export class TestAdminPluginResolver {
hydrateOrder(id: ID!): JSON
hydrateOrderReturnQuantities(id: ID!): JSON
hydrateChannel(id: ID!): JSON
hydrateChannelWithNestedRelation(id: ID!): JSON
}
`,
},
configuration: config => {
config.customFields.Channel.push({ name: 'thumb', type: 'relation', entity: Asset, nullable: true });
config.customFields.Channel.push({
name: 'additionalConfig',
type: 'relation',
entity: AdditionalConfig,
graphQLType: 'JSON',
nullable: true,
});
return config;
},
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ export class EntityHydrator {
visit(item, parts.slice());
}
}
} else if (target === null) {
result.push(target);
} else {
if (parts.length === 0) {
result.push(target);
Expand Down

0 comments on commit 4e1f408

Please sign in to comment.