1
0

eager-relations-bug.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import { Mutation, Resolver } from '@nestjs/graphql';
  2. import { DeepPartial } from '@vendure/common/lib/shared-types';
  3. import {
  4. ActiveOrderService,
  5. Ctx,
  6. CustomFieldRelationService,
  7. isGraphQlErrorResult,
  8. LanguageCode,
  9. Order,
  10. OrderService,
  11. PluginCommonModule,
  12. RequestContext,
  13. Transaction,
  14. TransactionalConnection,
  15. VendurePlugin,
  16. } from '@vendure/core';
  17. import { VendureEntity, EntityId, ID, OrderLine } from '@vendure/core';
  18. import gql from 'graphql-tag';
  19. import { Column, Entity, ManyToOne } from 'typeorm';
  20. @Entity()
  21. export class CutCode extends VendureEntity {
  22. constructor(input?: DeepPartial<CutCode>) {
  23. super(input);
  24. }
  25. @Column()
  26. code: string;
  27. }
  28. @Entity()
  29. class Cut extends VendureEntity {
  30. constructor(input?: DeepPartial<Cut>) {
  31. super(input);
  32. }
  33. @ManyToOne(() => OrderLine, { onDelete: 'CASCADE', nullable: true })
  34. orderLine: OrderLine;
  35. @EntityId()
  36. orderLineId: ID;
  37. // ---> BUG: This eager definition won't work as soon as the customField 'cuts' on the OrderLine is set to be eagerly loaded
  38. @ManyToOne(() => CutCode, { eager: true })
  39. code: CutCode;
  40. @EntityId()
  41. codeId: ID;
  42. @Column()
  43. name: string;
  44. }
  45. const commonApiExtensions = gql`
  46. type CutCode implements Node {
  47. id: ID!
  48. createdAt: DateTime!
  49. updatedAt: DateTime!
  50. code: String!
  51. }
  52. type Cut implements Node {
  53. id: ID!
  54. createdAt: DateTime!
  55. updatedAt: DateTime!
  56. orderLine: OrderLine!
  57. name: String!
  58. code: CutCode!
  59. }
  60. extend type Mutation {
  61. addCutToOrder: Order
  62. }
  63. `;
  64. @Resolver('Order')
  65. export class EagerRelationsBugOrderResolver {
  66. constructor(
  67. private connection: TransactionalConnection,
  68. private activeOrderService: ActiveOrderService,
  69. private orderService: OrderService,
  70. private customFieldRelationService: CustomFieldRelationService,
  71. ) {}
  72. @Transaction()
  73. @Mutation()
  74. async addCutToOrder(@Ctx() ctx: RequestContext): Promise<Order | null> {
  75. const sessionOrder = await this.activeOrderService.getActiveOrder(ctx, {}, true);
  76. const order = await this.orderService.findOne(ctx, sessionOrder.id);
  77. if (!order) {
  78. return null;
  79. }
  80. let orderLine = order.lines.length > 0 ? order.lines[0] : null;
  81. if (!orderLine) {
  82. const result = await this.orderService.addItemToOrder(ctx, sessionOrder.id, 1, 1);
  83. if (isGraphQlErrorResult(result)) {
  84. throw result.message;
  85. } else {
  86. orderLine = result.lines[result.lines.length - 1];
  87. }
  88. }
  89. let cut = await this.connection.getRepository(ctx, Cut).findOne({ where: { name: 'my-cut' } });
  90. if (!cut) {
  91. cut = new Cut({ name: 'my-cut' });
  92. }
  93. cut.orderLine = orderLine;
  94. let cutCode = await this.connection
  95. .getRepository(ctx, CutCode)
  96. .findOne({ where: { code: 'cut-code' } });
  97. if (!cutCode) {
  98. // Create dummy cutcode
  99. const newCutCode = new CutCode({ code: 'cut-code' });
  100. cutCode = await this.connection.getRepository(ctx, CutCode).save(newCutCode, { reload: true });
  101. }
  102. cut.code = cutCode;
  103. // Save cut
  104. cut = await this.connection.getRepository(ctx, Cut).save(cut, { reload: true });
  105. const customFields = {
  106. ...orderLine.customFields,
  107. cuts: [cut],
  108. };
  109. orderLine.customFields = customFields;
  110. // Save order line
  111. const savedOrderLine = await this.connection.getRepository(ctx, OrderLine).save(orderLine);
  112. await this.customFieldRelationService.updateRelations(
  113. ctx,
  114. OrderLine,
  115. { customFields },
  116. savedOrderLine,
  117. );
  118. return (await this.orderService.findOne(ctx, sessionOrder.id)) || null;
  119. }
  120. }
  121. @VendurePlugin({
  122. imports: [PluginCommonModule],
  123. providers: [],
  124. entities: [Cut, CutCode],
  125. shopApiExtensions: {
  126. resolvers: [EagerRelationsBugOrderResolver],
  127. schema: commonApiExtensions,
  128. },
  129. adminApiExtensions: {
  130. resolvers: [EagerRelationsBugOrderResolver],
  131. schema: commonApiExtensions,
  132. },
  133. configuration: config => {
  134. config.customFields.OrderLine.push(
  135. {
  136. name: 'cuts',
  137. type: 'relation',
  138. entity: Cut,
  139. list: true,
  140. eager: true, // ---> BUG: As soon as this relation is set to be loaded eagerly the eager relation to 'code' in the Cut entity won't be resolved anymore.
  141. label: [
  142. {
  143. languageCode: LanguageCode.en,
  144. value: 'Cuts',
  145. },
  146. ],
  147. },
  148. {
  149. name: 'comment',
  150. type: 'string',
  151. label: [
  152. {
  153. languageCode: LanguageCode.en,
  154. value: 'Comment',
  155. },
  156. ],
  157. },
  158. );
  159. return config;
  160. },
  161. compatibility: '^2.1.0',
  162. })
  163. export class EagerRelationsBugPlugin {}