Răsfoiți Sursa

perf(core): Remove the @RelationId() decorator from OrderItem

It turns out that the @RelationId() decorator has some serious perf issues: https://github.com/typeorm/typeorm/issues/3507
Analysis of queries shows that a SELECT was being performed for *each* OrderItem in an Order, which noticeably impacts performance.
Relates to #226
Michael Bromley 6 ani în urmă
părinte
comite
6bda232399

+ 1 - 1
packages/core/e2e/order.e2e-spec.ts

@@ -745,7 +745,7 @@ describe('Orders resolver', () => {
             );
 
             expect(cancelOrder.lines[0].quantity).toBe(1);
-            expect(cancelOrder.lines[0].items).toEqual([
+            expect(cancelOrder.lines[0].items.sort((a, b) => (a.id < b.id ? -1 : 1))).toEqual([
                 { id: 'T_13', cancelled: true },
                 { id: 'T_14', cancelled: false },
             ]);

+ 2 - 7
packages/core/src/entity/order-item/order-item.entity.ts

@@ -48,13 +48,8 @@ export class OrderItem extends VendureEntity {
     @OneToOne(type => Cancellation, cancellation => cancellation.orderItem)
     cancellation: Cancellation;
 
-    @RelationId('cancellation')
-    cancellationId: ID | null;
-
-    @Calculated()
-    get cancelled(): boolean {
-        return !!this.cancellationId;
-    }
+    @Column({ default: false })
+    cancelled: boolean;
 
     @Calculated()
     get unitPriceWithTax(): number {

+ 1 - 1
packages/core/src/entity/order-line/order-line.entity.ts

@@ -75,7 +75,7 @@ export class OrderLine extends VendureEntity implements HasCustomFields {
     }
 
     get activeItems(): OrderItem[] {
-        return (this.items || []).filter(i => !i.cancellationId);
+        return (this.items || []).filter(i => !i.cancelled);
     }
 
     /**

+ 7 - 3
packages/core/src/service/services/order.service.ts

@@ -554,7 +554,7 @@ export class OrderService {
         }
         const { items, orders } = await this.getOrdersAndItemsFromLines(
             lines,
-            i => !i.cancellationId,
+            i => !i.cancelled,
             'error.cancel-order-lines-quantity-too-high',
         );
         if (1 < orders.length) {
@@ -569,7 +569,11 @@ export class OrderService {
                 state: order.state,
             });
         }
+
+        // Perform the cancellation
         await this.stockMovementService.createCancellationsForOrderItems(items);
+        items.forEach(i => (i.cancelled = true));
+        await this.connection.getRepository(OrderItem).save(items, { reload: false });
 
         const orderWithItems = await this.connection.getRepository(Order).findOne(order.id, {
             relations: ['lines', 'lines.items'],
@@ -588,7 +592,7 @@ export class OrderService {
         });
         const allOrderItemsCancelled = orderWithItems.lines
             .reduce((orderItems, line) => [...orderItems, ...line.items], [] as OrderItem[])
-            .every(orderItem => !!orderItem.cancellationId);
+            .every(orderItem => orderItem.cancelled);
         return allOrderItemsCancelled;
     }
 
@@ -603,7 +607,7 @@ export class OrderService {
         }
         const { items, orders } = await this.getOrdersAndItemsFromLines(
             input.lines,
-            i => !i.cancellationId,
+            i => !i.cancelled,
             'error.refund-order-lines-quantity-too-high',
         );
         if (1 < orders.length) {

+ 1 - 1
packages/core/src/service/services/stock-movement.service.ts

@@ -111,7 +111,7 @@ export class StockMovementService {
 
             if (productVariant.trackInventory === true) {
                 productVariant.stockOnHand += 1;
-                await this.connection.getRepository(ProductVariant).save(productVariant);
+                await this.connection.getRepository(ProductVariant).save(productVariant, { reload: false });
             }
         }
         return this.connection.getRepository(Cancellation).save(cancellations);