From 121b42acfe98c12dd593f9b1f2072ff0f3b61724 Mon Sep 17 00:00:00 2001 From: Riqwan Thamir Date: Wed, 15 Feb 2023 16:25:30 +0100 Subject: [PATCH] chore(medusa): Typeorm upgrade to 0.3.11 (#3041) --- .changeset/brave-guests-mate.md | 16 + .github/workflows/test-cli-with-database.yml | 3 +- .../__tests__/admin/order-edit/order-edit.js | 4 +- .../api/__tests__/admin/order/order.js | 4 +- .../api/__tests__/admin/price-list.js | 108 +-- .../api/__tests__/admin/product.js | 77 +- .../api/__tests__/admin/shipping-options.js | 14 +- .../api/__tests__/admin/store.js | 4 +- .../__snapshots__/product-variants.js.snap | 5 + .../tax-calculation-ff-tax-inclusive.js | 78 +- .../api/__tests__/store/orders.js | 12 +- .../api/__tests__/store/returns.js | 4 +- .../api/__tests__/store/shipping-options.js | 11 +- .../api/__tests__/store/swaps.js | 10 +- .../api/factories/simple-address-factory.ts | 6 +- .../simple-analytics-config-factory.ts | 6 +- .../api/factories/simple-batch-job-factory.ts | 6 +- .../api/factories/simple-cart-factory.ts | 22 +- .../simple-custom-shipping-option-factory.ts | 12 +- .../api/factories/simple-customer-factory.ts | 17 +- .../simple-customer-group-factory.ts | 6 +- .../simple-discount-condition-factory.ts | 6 +- .../api/factories/simple-discount-factory.ts | 12 +- .../api/factories/simple-gift-card-factory.ts | 6 +- .../api/factories/simple-line-item-factory.ts | 6 +- .../factories/simple-order-edit-factory.ts | 8 +- .../api/factories/simple-order-factory.ts | 20 +- .../simple-order-item-change-factory.ts | 12 +- .../simple-payment-collection-factory.ts | 10 +- .../api/factories/simple-payment-factory.ts | 6 +- .../factories/simple-price-list-factory.ts | 8 +- .../simple-product-category-factory.ts | 10 +- .../simple-product-collection-factory.ts | 6 +- .../api/factories/simple-product-factory.ts | 36 +- .../simple-product-tax-rate-factory.ts | 6 +- .../simple-product-type-tax-rate-factory.ts | 6 +- .../simple-product-variant-factory.ts | 8 +- .../simple-publishable-api-key-factory.ts | 6 +- .../api/factories/simple-region-factory.ts | 6 +- .../factories/simple-sales-channel-factory.ts | 8 +- .../simple-shipping-method-factory.ts | 10 +- .../simple-shipping-option-factory.ts | 16 +- .../simple-shipping-tax-rate-factory.ts | 6 +- .../api/factories/simple-tax-rate-factory.ts | 6 +- integration-tests/api/helpers/admin-seeder.js | 4 +- .../api/helpers/admin-variants-seeder.js | 6 +- .../api/helpers/batch-job-seeder.js | 4 +- integration-tests/api/helpers/cart-seeder.js | 9 +- integration-tests/api/helpers/claim-seeder.js | 4 +- .../api/helpers/customer-seeder.js | 4 +- .../api/helpers/discount-seeder.js | 4 +- .../api/helpers/draft-order-seeder.js | 9 +- integration-tests/api/helpers/order-seeder.js | 9 +- .../api/helpers/price-list-seeder.js | 4 +- .../api/helpers/price-selection-seeder.js | 7 +- .../api/helpers/product-seeder.js | 10 +- .../api/helpers/shipping-option-seeder.js | 7 +- .../api/helpers/store-product-seeder.js | 7 +- integration-tests/api/helpers/swap-seeder.js | 6 +- integration-tests/api/helpers/user-seeder.js | 4 +- integration-tests/api/package.json | 2 +- integration-tests/helpers/use-db.js | 36 +- integration-tests/helpers/use-template-db.js | 55 +- .../inventory/inventory-items/index.js | 7 +- .../__snapshots__/index.js.snap | 16 +- .../__tests__/medusa-plugin-sendgrid/index.js | 9 +- .../factories/simple-product-factory.ts | 17 +- .../simple-shipping-option-factory.ts | 11 +- .../plugins/factories/simple-store-factory.ts | 15 +- .../plugins/helpers/cart-seeder.js | 9 +- .../plugins/helpers/draft-order-seeder.js | 5 +- .../plugins/helpers/order-seeder.js | 5 +- .../plugins/helpers/product-seeder.js | 5 +- .../plugins/helpers/shipping-option-seeder.js | 5 +- integration-tests/plugins/package.json | 2 +- .../__tests__/product-categories/queries.ts | 6 +- integration-tests/repositories/package.json | 2 +- package.json | 2 +- packages/inventory/package.json | 6 +- .../inventory/src/services/inventory-item.ts | 10 +- .../inventory/src/services/inventory-level.ts | 12 +- .../src/services/reservation-item.ts | 8 +- packages/inventory/src/utils/query.ts | 22 +- .../src/transform-idable-fields.ts | 2 +- packages/medusa-file-minio/package.json | 6 +- packages/medusa-interfaces/package.json | 1 - .../src/__tests__/base-service.js | 27 - .../medusa-interfaces/src/base-service.js | 142 +--- .../src/services/sendgrid.js | 43 +- .../medusa-test-utils/src/mock-manager.js | 12 +- .../medusa-test-utils/src/mock-repository.js | 75 +- packages/medusa/package.json | 2 +- .../inventory-items/utils/join-variants.ts | 11 +- .../api/routes/admin/orders/create-swap.ts | 2 + .../src/api/routes/admin/orders/index.ts | 2 + .../routes/admin/shipping-options/index.ts | 2 +- .../update-shipping-option.ts | 11 +- .../routes/admin/swaps/__tests__/get-swap.js | 1 + .../src/api/routes/admin/swaps/index.ts | 1 + .../src/api/routes/admin/variants/index.ts | 2 + .../src/api/routes/store/carts/index.ts | 1 + .../routes/store/carts/update-line-item.ts | 2 +- .../src/api/routes/store/orders/index.ts | 1 - .../src/api/routes/store/swaps/create-swap.ts | 2 + .../src/api/routes/store/swaps/index.ts | 1 + .../store/variants/__tests__/get-variant.js | 2 +- .../src/api/routes/store/variants/index.ts | 2 +- packages/medusa/src/commands/migrate.js | 58 +- .../src/loaders/__tests__/default.spec.ts | 37 +- packages/medusa/src/loaders/database.ts | 58 +- packages/medusa/src/loaders/defaults.ts | 8 +- packages/medusa/src/loaders/index.ts | 20 +- packages/medusa/src/loaders/repositories.ts | 22 +- .../medusa/src/models/discount-condition.ts | 2 + packages/medusa/src/models/line-item.ts | 2 +- packages/medusa/src/models/order.ts | 11 +- packages/medusa/src/models/product-variant.ts | 17 +- packages/medusa/src/repositories/address.ts | 8 +- .../src/repositories/analytics-config.ts | 6 +- packages/medusa/src/repositories/batch-job.ts | 6 +- packages/medusa/src/repositories/cart.ts | 56 +- .../medusa/src/repositories/claim-image.ts | 6 +- .../medusa/src/repositories/claim-item.ts | 6 +- packages/medusa/src/repositories/claim-tag.ts | 6 +- packages/medusa/src/repositories/claim.ts | 6 +- packages/medusa/src/repositories/country.ts | 6 +- packages/medusa/src/repositories/currency.ts | 6 +- .../repositories/custom-shipping-option.ts | 10 +- .../medusa/src/repositories/customer-group.ts | 237 +++--- packages/medusa/src/repositories/customer.ts | 78 +- .../src/repositories/discount-condition.ts | 550 +++++++------ .../medusa/src/repositories/discount-rule.ts | 8 +- packages/medusa/src/repositories/discount.ts | 8 +- .../medusa/src/repositories/draft-order.ts | 8 +- .../src/repositories/fulfillment-provider.ts | 10 +- .../medusa/src/repositories/fulfillment.ts | 8 +- .../src/repositories/gift-card-transaction.ts | 10 +- packages/medusa/src/repositories/gift-card.ts | 164 +--- .../src/repositories/idempotency-key.ts | 8 +- packages/medusa/src/repositories/image.ts | 15 +- packages/medusa/src/repositories/invite.ts | 8 +- .../src/repositories/line-item-adjustment.ts | 10 +- .../src/repositories/line-item-tax-line.ts | 63 +- packages/medusa/src/repositories/line-item.ts | 11 +- .../medusa/src/repositories/money-amount.ts | 454 +++++------ packages/medusa/src/repositories/note.ts | 8 +- .../src/repositories/notification-provider.ts | 8 +- .../medusa/src/repositories/notification.ts | 8 +- packages/medusa/src/repositories/oauth.ts | 8 +- .../medusa/src/repositories/order-edit.ts | 8 +- .../src/repositories/order-item-change.ts | 10 +- packages/medusa/src/repositories/order.ts | 28 +- .../src/repositories/payment-collection.ts | 110 +-- .../src/repositories/payment-provider.ts | 9 +- .../src/repositories/payment-session.ts | 8 +- packages/medusa/src/repositories/payment.ts | 8 +- .../medusa/src/repositories/price-list.ts | 139 +--- .../src/repositories/product-category.ts | 209 ++--- .../src/repositories/product-collection.ts | 54 +- .../src/repositories/product-option-value.ts | 10 +- .../medusa/src/repositories/product-option.ts | 8 +- .../medusa/src/repositories/product-tag.ts | 125 ++- .../src/repositories/product-tax-rate.ts | 8 +- .../medusa/src/repositories/product-type.ts | 85 +- .../src/repositories/product-variant.ts | 254 +----- packages/medusa/src/repositories/product.ts | 737 ++++++------------ .../publishable-api-key-sales-channel.ts | 171 ++-- .../src/repositories/publishable-api-key.ts | 73 +- packages/medusa/src/repositories/refund.ts | 8 +- packages/medusa/src/repositories/region.ts | 8 +- .../medusa/src/repositories/return-item.ts | 8 +- .../medusa/src/repositories/return-reason.ts | 8 +- packages/medusa/src/repositories/return.ts | 8 +- .../medusa/src/repositories/sales-channel.ts | 191 ++--- .../repositories/shipping-method-tax-line.ts | 72 +- .../src/repositories/shipping-method.ts | 8 +- .../shipping-option-requirement.ts | 11 +- .../src/repositories/shipping-option.ts | 36 +- .../src/repositories/shipping-profile.ts | 9 +- .../src/repositories/shipping-tax-rate.ts | 9 +- .../medusa/src/repositories/staged-job.ts | 8 +- packages/medusa/src/repositories/store.ts | 8 +- packages/medusa/src/repositories/swap.ts | 56 +- .../medusa/src/repositories/tax-provider.ts | 8 +- packages/medusa/src/repositories/tax-rate.ts | 48 +- .../medusa/src/repositories/tracking-link.ts | 8 +- packages/medusa/src/repositories/user.ts | 8 +- .../src/scripts/discount-rule-migration.ts | 44 +- .../medusa/src/services/__tests__/cart.js | 94 ++- .../medusa/src/services/__tests__/claim.js | 2 +- .../__tests__/custom-shipping-option.js | 9 +- .../medusa/src/services/__tests__/customer.js | 2 +- .../src/services/__tests__/gift-card.js | 40 +- .../medusa/src/services/__tests__/invite.js | 6 +- .../__tests__/line-item-adjustment.js | 4 +- .../medusa/src/services/__tests__/note.js | 6 +- .../__tests__/order-edit-item-change.ts | 11 +- .../medusa/src/services/__tests__/order.js | 2 +- .../src/services/__tests__/price-list.js | 2 +- .../src/services/__tests__/product-variant.js | 3 + .../medusa/src/services/__tests__/product.js | 18 +- .../services/__tests__/publishable-api-key.ts | 17 +- .../medusa/src/services/__tests__/region.ts | 2 +- .../src/services/__tests__/sales-channel.ts | 45 +- .../src/services/__tests__/shipping-option.js | 13 +- .../medusa/src/services/__tests__/swap.ts | 81 +- .../medusa/src/services/analytics-config.ts | 8 +- packages/medusa/src/services/batch-job.ts | 14 +- packages/medusa/src/services/cart.ts | 146 ++-- packages/medusa/src/services/claim-item.ts | 26 +- packages/medusa/src/services/claim.ts | 32 +- packages/medusa/src/services/csv-parser.ts | 2 +- packages/medusa/src/services/currency.ts | 6 +- .../src/services/custom-shipping-option.ts | 6 +- .../medusa/src/services/customer-group.ts | 21 +- packages/medusa/src/services/customer.ts | 60 +- .../medusa/src/services/discount-condition.ts | 14 +- packages/medusa/src/services/discount.ts | 60 +- packages/medusa/src/services/draft-order.ts | 85 +- packages/medusa/src/services/event-bus.ts | 4 +- .../src/services/fulfillment-provider.ts | 4 +- packages/medusa/src/services/fulfillment.ts | 12 +- packages/medusa/src/services/gift-card.ts | 70 +- .../medusa/src/services/idempotency-key.ts | 8 +- packages/medusa/src/services/invite.ts | 18 +- .../src/services/line-item-adjustment.ts | 22 +- packages/medusa/src/services/line-item.ts | 34 +- packages/medusa/src/services/note.ts | 10 +- packages/medusa/src/services/notification.ts | 10 +- packages/medusa/src/services/oauth.ts | 18 +- .../src/services/order-edit-item-change.ts | 8 +- packages/medusa/src/services/order-edit.ts | 66 +- packages/medusa/src/services/order.ts | 177 +++-- .../medusa/src/services/payment-collection.ts | 16 +- .../medusa/src/services/payment-provider.ts | 36 +- packages/medusa/src/services/payment.ts | 6 +- packages/medusa/src/services/price-list.ts | 119 ++- .../medusa/src/services/product-category.ts | 20 +- .../medusa/src/services/product-collection.ts | 67 +- packages/medusa/src/services/product-tag.ts | 20 +- .../medusa/src/services/product-tax-rate.ts | 2 +- packages/medusa/src/services/product-type.ts | 15 +- .../medusa/src/services/product-variant.ts | 174 ++--- packages/medusa/src/services/product.ts | 145 ++-- .../src/services/publishable-api-key.ts | 43 +- packages/medusa/src/services/region.ts | 59 +- packages/medusa/src/services/return-reason.ts | 10 +- packages/medusa/src/services/return.ts | 22 +- packages/medusa/src/services/sales-channel.ts | 28 +- .../medusa/src/services/shipping-option.ts | 60 +- .../medusa/src/services/shipping-profile.ts | 31 +- .../medusa/src/services/shipping-tax-rate.ts | 3 +- packages/medusa/src/services/store.ts | 33 +- packages/medusa/src/services/swap.ts | 48 +- packages/medusa/src/services/tax-provider.ts | 20 +- packages/medusa/src/services/tax-rate.ts | 41 +- packages/medusa/src/services/user.ts | 18 +- .../strategies/__tests__/price-selection.js | 2 +- .../medusa/src/strategies/cart-completion.ts | 4 +- .../medusa/src/strategies/price-selection.ts | 4 +- packages/medusa/src/types/common.ts | 40 +- packages/medusa/src/types/order-edit.ts | 3 + packages/medusa/src/types/product.ts | 8 + .../src/utils/__tests__/build-query.spec.ts | 310 +++++++- packages/medusa/src/utils/build-query.ts | 390 +++++++-- .../utils/idempotency/run-idempotency-step.ts | 6 +- packages/medusa/src/utils/index.ts | 2 + packages/medusa/src/utils/is-date.ts | 4 + packages/medusa/src/utils/is-object.ts | 3 + packages/medusa/src/utils/naming-strategy.ts | 24 +- packages/medusa/src/utils/repository.ts | 15 +- packages/medusa/tsconfig.json | 3 +- packages/stock-location/package.json | 4 +- .../src/services/stock-location.ts | 2 +- yarn.lock | 93 +-- 275 files changed, 4494 insertions(+), 4781 deletions(-) create mode 100644 .changeset/brave-guests-mate.md create mode 100644 packages/medusa/src/utils/is-date.ts create mode 100644 packages/medusa/src/utils/is-object.ts diff --git a/.changeset/brave-guests-mate.md b/.changeset/brave-guests-mate.md new file mode 100644 index 0000000000..72a4fa76f6 --- /dev/null +++ b/.changeset/brave-guests-mate.md @@ -0,0 +1,16 @@ +--- +"@medusajs/medusa": minor +"medusa-plugin-sendgrid": patch +"medusa-payment-stripe": patch +"medusa-plugin-algolia": patch +"medusa-source-shopify": patch +"medusa-core-utils": patch +"medusa-file-minio": patch +"medusa-interfaces": patch +"medusa-test-utils": patch +"@medusajs/stock-location": patch +"@medusajs/inventory": patch +"@medusajs/medusa-js": patch +--- + +chore(medusa): upgrade typeorm from 0.2.51 to 0.3.11 diff --git a/.github/workflows/test-cli-with-database.yml b/.github/workflows/test-cli-with-database.yml index 4664fa3f89..4dad8b75b6 100644 --- a/.github/workflows/test-cli-with-database.yml +++ b/.github/workflows/test-cli-with-database.yml @@ -58,8 +58,9 @@ jobs: run: npm i -g @medusajs/medusa-cli - name: Create Medusa project + # TODO: Remove the branch when typeorm is no longer a dependency for starter run: | - medusa new cli-test + medusa new cli-test 'https://github.com/medusajs/medusa-starter-default/tree/typeorm-upgrade' working-directory: .. - name: Install postgres config diff --git a/integration-tests/api/__tests__/admin/order-edit/order-edit.js b/integration-tests/api/__tests__/admin/order-edit/order-edit.js index c8c3a2c1d1..59f1ecf4ed 100644 --- a/integration-tests/api/__tests__/admin/order-edit/order-edit.js +++ b/integration-tests/api/__tests__/admin/order-edit/order-edit.js @@ -470,7 +470,7 @@ describe("/admin/order-edits", () => { withDeleted: true, }) - expect(orderEdit).toBeUndefined() + expect(orderEdit).toBeNull() expect(response.status).toEqual(200) expect(response.data).toEqual({ id, @@ -534,7 +534,7 @@ describe("/admin/order-edits", () => { withDeleted: true, }) - expect(orderEdit).toBeUndefined() + expect(orderEdit).toBeNull() expect(response.status).toEqual(200) expect(response.data).toEqual({ id: orderEditId, diff --git a/integration-tests/api/__tests__/admin/order/order.js b/integration-tests/api/__tests__/admin/order/order.js index 83275376a5..f1782e89fd 100644 --- a/integration-tests/api/__tests__/admin/order/order.js +++ b/integration-tests/api/__tests__/admin/order/order.js @@ -2123,7 +2123,9 @@ describe("/admin/orders", () => { const manager = dbConnection.manager const customOptions = await manager.find(CustomShippingOption, { - shipping_option_id: "test-option", + where: { + shipping_option_id: "test-option", + }, }) expect(response.status).toEqual(200) diff --git a/integration-tests/api/__tests__/admin/price-list.js b/integration-tests/api/__tests__/admin/price-list.js index d0bdc1aa1c..e66d8e9ccb 100644 --- a/integration-tests/api/__tests__/admin/price-list.js +++ b/integration-tests/api/__tests__/admin/price-list.js @@ -23,7 +23,7 @@ const adminReqConfig = { }, } -jest.setTimeout(30000) +jest.setTimeout(50000) describe("/admin/price-lists", () => { let medusaProcess @@ -1108,52 +1108,66 @@ describe("/admin/price-lists", () => { expect(response.status).toEqual(200) expect(response.data.count).toEqual(2) expect(response.data.products).toHaveLength(2) - expect(response.data.products).toEqual([ - expect.objectContaining({ - id: "test-prod-2", - variants: expect.arrayContaining([ - expect.objectContaining({ - id: "test-variant-3", - prices: expect.arrayContaining([ - expect.objectContaining({ currency_code: "usd", amount: 100 }), - ]), - }), - expect.objectContaining({ - id: "test-variant-4", - prices: expect.arrayContaining([ - expect.objectContaining({ currency_code: "usd", amount: 100 }), - expect.objectContaining({ - currency_code: "usd", - amount: 150, - price_list_id: "test-list", - }), - ]), - }), - ]), - }), - expect.objectContaining({ - id: "test-prod-1", - variants: expect.arrayContaining([ - expect.objectContaining({ - id: "test-variant-1", - prices: expect.arrayContaining([ - expect.objectContaining({ currency_code: "usd", amount: 100 }), - expect.objectContaining({ - currency_code: "usd", - amount: 150, - price_list_id: "test-list", - }), - ]), - }), - expect.objectContaining({ - id: "test-variant-2", - prices: expect.arrayContaining([ - expect.objectContaining({ currency_code: "usd", amount: 100 }), - ]), - }), - ]), - }), - ]) + expect(response.data.products).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "test-prod-1", + variants: expect.arrayContaining([ + expect.objectContaining({ + id: "test-variant-1", + prices: expect.arrayContaining([ + expect.objectContaining({ + currency_code: "usd", + amount: 100, + }), + expect.objectContaining({ + currency_code: "usd", + amount: 150, + price_list_id: "test-list", + }), + ]), + }), + expect.objectContaining({ + id: "test-variant-2", + prices: expect.arrayContaining([ + expect.objectContaining({ + currency_code: "usd", + amount: 100, + }), + ]), + }), + ]), + }), + expect.objectContaining({ + id: "test-prod-2", + variants: expect.arrayContaining([ + expect.objectContaining({ + id: "test-variant-3", + prices: expect.arrayContaining([ + expect.objectContaining({ + currency_code: "usd", + amount: 100, + }), + ]), + }), + expect.objectContaining({ + id: "test-variant-4", + prices: expect.arrayContaining([ + expect.objectContaining({ + currency_code: "usd", + amount: 100, + }), + expect.objectContaining({ + currency_code: "usd", + amount: 150, + price_list_id: "test-list", + }), + ]), + }), + ]), + }), + ]) + ) }) it("lists only product 2", async () => { diff --git a/integration-tests/api/__tests__/admin/product.js b/integration-tests/api/__tests__/admin/product.js index 8e45bb1042..26c9e5105c 100644 --- a/integration-tests/api/__tests__/admin/product.js +++ b/integration-tests/api/__tests__/admin/product.js @@ -2142,7 +2142,6 @@ describe("/admin/products", () => { const variant = response.data.product.variants.find( (v) => v.id === variantId ) - expect(variant.prices.length).toEqual(data.prices.length) expect(variant.prices).toEqual( @@ -2467,10 +2466,10 @@ describe("/admin/products", () => { const api = useApi() const variantPre = await dbConnection.manager.findOne(ProductVariant, { - id: "test-variant", + where: { id: "test-variant" }, }) - expect(variantPre).not.toEqual(undefined) + expect(variantPre).toBeTruthy() const response = await api .delete("/admin/products/test-product", adminHeaders) @@ -2488,10 +2487,10 @@ describe("/admin/products", () => { ) const variant = await dbConnection.manager.findOne(ProductVariant, { - id: "test-variant", + where: { id: "test-variant" }, }) - expect(variant).toEqual(undefined) + expect(variant).not.toBeTruthy() }) it("successfully deletes a product variant and its associated option values", async () => { @@ -2499,10 +2498,10 @@ describe("/admin/products", () => { // Validate that the option value exists const optValPre = await dbConnection.manager.findOne(ProductOptionValue, { - variant_id: "test-variant_2", + where: { variant_id: "test-variant_2" }, }) - expect(optValPre).not.toEqual(undefined) + expect(optValPre).toBeTruthy() // Soft delete the variant const response = await api.delete( @@ -2515,20 +2514,18 @@ describe("/admin/products", () => { // Validate that the option value was deleted const optValPost = await dbConnection.manager.findOne( ProductOptionValue, - { - variant_id: "test-variant_2", - } + { where: { variant_id: "test-variant_2" } } ) - expect(optValPost).toEqual(undefined) + expect(optValPost).not.toBeTruthy() // Validate that the option still exists in the DB with deleted_at const optValDeleted = await dbConnection.manager.findOne( ProductOptionValue, { - variant_id: "test-variant_2", - }, - { + where: { + variant_id: "test-variant_2", + }, withDeleted: true, } ) @@ -2546,10 +2543,10 @@ describe("/admin/products", () => { // Validate that the option value exists const optValPre = await dbConnection.manager.findOne(ProductOptionValue, { - variant_id: "test-variant_2", + where: { variant_id: "test-variant_2" }, }) - expect(optValPre).not.toEqual(undefined) + expect(optValPre).toBeTruthy() // Soft delete the product const response = await api.delete( @@ -2563,19 +2560,19 @@ describe("/admin/products", () => { const optValPost = await dbConnection.manager.findOne( ProductOptionValue, { - variant_id: "test-variant_2", + where: { variant_id: "test-variant_2" }, } ) - expect(optValPost).toEqual(undefined) + expect(optValPost).not.toBeTruthy() // Validate that the option still exists in the DB with deleted_at const optValDeleted = await dbConnection.manager.findOne( ProductOptionValue, { - variant_id: "test-variant_2", - }, - { + where: { + variant_id: "test-variant_2", + }, withDeleted: true, } ) @@ -2593,10 +2590,10 @@ describe("/admin/products", () => { // Validate that the price exists const pricePre = await dbConnection.manager.findOne(MoneyAmount, { - id: "test-price", + where: { id: "test-price" }, }) - expect(pricePre).not.toEqual(undefined) + expect(pricePre).toBeTruthy() // Soft delete the variant const response = await api.delete( @@ -2608,21 +2605,18 @@ describe("/admin/products", () => { // Validate that the price was deleted const pricePost = await dbConnection.manager.findOne(MoneyAmount, { - id: "test-price", + where: { id: "test-price" }, }) - expect(pricePost).toEqual(undefined) + expect(pricePost).not.toBeTruthy() // Validate that the price still exists in the DB with deleted_at - const optValDeleted = await dbConnection.manager.findOne( - MoneyAmount, - { + const optValDeleted = await dbConnection.manager.findOne(MoneyAmount, { + where: { id: "test-price", }, - { - withDeleted: true, - } - ) + withDeleted: true, + }) expect(optValDeleted).toEqual( expect.objectContaining({ @@ -2637,10 +2631,10 @@ describe("/admin/products", () => { // Validate that the price exists const pricePre = await dbConnection.manager.findOne(MoneyAmount, { - id: "test-price", + where: { id: "test-price" }, }) - expect(pricePre).not.toEqual(undefined) + expect(pricePre).toBeTruthy() // Soft delete the product const response = await api.delete( @@ -2652,21 +2646,18 @@ describe("/admin/products", () => { // Validate that the price has been deleted const pricePost = await dbConnection.manager.findOne(MoneyAmount, { - id: "test-price", + where: { id: "test-price" }, }) - expect(pricePost).toEqual(undefined) + expect(pricePost).not.toBeTruthy() // Validate that the price still exists in the DB with deleted_at - const optValDeleted = await dbConnection.manager.findOne( - MoneyAmount, - { + const optValDeleted = await dbConnection.manager.findOne(MoneyAmount, { + where: { id: "test-price", }, - { - withDeleted: true, - } - ) + withDeleted: true, + }) expect(optValDeleted).toEqual( expect.objectContaining({ diff --git a/integration-tests/api/__tests__/admin/shipping-options.js b/integration-tests/api/__tests__/admin/shipping-options.js index 396c0bd155..95ebdca49c 100644 --- a/integration-tests/api/__tests__/admin/shipping-options.js +++ b/integration-tests/api/__tests__/admin/shipping-options.js @@ -92,7 +92,7 @@ describe("/admin/shipping-options", () => { ) }) - it("fails as it is not allowed to set id from client side", async () => { + it("fails to add a a requirement with an id if it does not exists", async () => { const api = useApi() const payload = { @@ -123,7 +123,9 @@ describe("/admin/shipping-options", () => { }) expect(res.status).toEqual(400) - expect(res.data.message).toEqual("ID does not exist") + expect(res.data.message).toEqual( + "Shipping option requirement with id not_allowed does not exist" + ) }) it("it successfully updates a set of existing requirements", async () => { @@ -274,7 +276,9 @@ describe("/admin/shipping-options", () => { const manager = dbConnection.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfile.default, + }, }) payload = { @@ -521,7 +525,9 @@ describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] /admin/shipping-options", () => { const defaultProfile = await dbConnection.manager.findOne( ShippingProfile, { - type: "default", + where: { + type: ShippingProfile.default, + }, } ) diff --git a/integration-tests/api/__tests__/admin/store.js b/integration-tests/api/__tests__/admin/store.js index 5f5e78d2d5..fc93e339e1 100644 --- a/integration-tests/api/__tests__/admin/store.js +++ b/integration-tests/api/__tests__/admin/store.js @@ -75,7 +75,9 @@ describe("/admin/store", () => { medusaProcess = await setupServer({ cwd }) const manager = dbConnection.manager - const store = await manager.findOne(Store, { name: "Medusa Store" }) + const store = await manager.findOne(Store, { + where: { name: "Medusa Store" }, + }) await manager.query( `INSERT INTO store_currencies (store_id, currency_code) VALUES ('${store.id}', 'dkk')` ) diff --git a/integration-tests/api/__tests__/store/__snapshots__/product-variants.js.snap b/integration-tests/api/__tests__/store/__snapshots__/product-variants.js.snap index c1555f4c49..02a1a260e2 100644 --- a/integration-tests/api/__tests__/store/__snapshots__/product-variants.js.snap +++ b/integration-tests/api/__tests__/store/__snapshots__/product-variants.js.snap @@ -59,6 +59,7 @@ Object { "title": "Test variant", "upc": "test-upc", "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -150,6 +151,7 @@ Object { "title": "Test variant", "upc": "test-upc", "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -216,6 +218,7 @@ Object { "title": "test2", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -314,6 +317,7 @@ Object { "title": "Test variant", "upc": "test-upc", "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -380,6 +384,7 @@ Object { "title": "Test variant", "upc": "test-upc", "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, diff --git a/integration-tests/api/__tests__/store/cart/gift-cards/tax-calculation-ff-tax-inclusive.js b/integration-tests/api/__tests__/store/cart/gift-cards/tax-calculation-ff-tax-inclusive.js index c7112228ce..b5edf586f2 100644 --- a/integration-tests/api/__tests__/store/cart/gift-cards/tax-calculation-ff-tax-inclusive.js +++ b/integration-tests/api/__tests__/store/cart/gift-cards/tax-calculation-ff-tax-inclusive.js @@ -52,7 +52,9 @@ describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] Gift Card - Tax calculations", () => includes_tax: true, }) - customer = await simpleCustomerFactory(dbConnection, { password: 'medusatest' }) + customer = await simpleCustomerFactory(dbConnection, { + password: "medusatest", + }) customerData = { email: customer.email, password: "medusatest", @@ -64,15 +66,19 @@ describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] Gift Card - Tax calculations", () => is_giftcard: true, discountable: false, options: [{ id: "denom", title: "Denomination" }], - variants: [{ - title: "Gift Card", - prices: [{ - amount: 30000, - currency: "usd", - region_id: region.id, - }], - options: [{ option_id: "denom", value: "Denomination" }], - }] + variants: [ + { + title: "Gift Card", + prices: [ + { + amount: 30000, + currency: "usd", + region_id: region.id, + }, + ], + options: [{ option_id: "denom", value: "Denomination" }], + }, + ], }) }) @@ -84,10 +90,12 @@ describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] Gift Card - Tax calculations", () => const createCartRes = await api.post("/store/carts", { region_id: region.id, - items: [{ - variant_id: product.variants[0].id, - quantity: 1, - }], + items: [ + { + variant_id: product.variants[0].id, + quantity: 1, + }, + ], }) expect(createCartRes.status).toEqual(200) @@ -112,8 +120,8 @@ describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] Gift Card - Tax calculations", () => id: product.variants[0].id, product: expect.objectContaining({ is_giftcard: true, - }) - }) + }), + }), }), ]) ) @@ -142,10 +150,12 @@ describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] Gift Card - Tax calculations", () => const getCartResponse = await api.get(`/store/carts/${cartFactory.id}`) const cart = getCartResponse.data.cart await api.post(`/store/carts/${cart.id}/payment-sessions`) - const createdOrder = await api.post(`/store/carts/${cart.id}/complete-cart`) + const createdOrder = await api.post( + `/store/carts/${cart.id}/complete-cart` + ) const createdGiftCards = await dbConnection.manager.find(GiftCard, { - where: { order_id: createdOrder.data.data.id } + where: { order_id: createdOrder.data.data.id }, }) const createdGiftCard = createdGiftCards[0] @@ -166,14 +176,18 @@ describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] Gift Card - Tax calculations", () => tax_rate: region.tax_rate, }) const expensiveProduct = await simpleProductFactory(dbConnection, { - variants: [{ - title: "Product cost higher than gift card balance", - prices: [{ - amount: 50000, - currency: "usd", - region_id: region.id, - }], - }] + variants: [ + { + title: "Product cost higher than gift card balance", + prices: [ + { + amount: 50000, + currency: "usd", + region_id: region.id, + }, + ], + }, + ], }) const customerRes = await api.post("/store/customers", customerData, { @@ -203,7 +217,9 @@ describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] Gift Card - Tax calculations", () => const getCartResponse = await api.get(`/store/carts/${cartFactory.id}`) const cart = getCartResponse.data.cart await api.post(`/store/carts/${cart.id}/payment-sessions`) - const createdOrder = await api.post(`/store/carts/${cart.id}/complete-cart`) + const createdOrder = await api.post( + `/store/carts/${cart.id}/complete-cart` + ) expect(createdOrder.data.data).toEqual( expect.objectContaining({ @@ -232,12 +248,12 @@ describe("[MEDUSA_FF_TAX_INCLUSIVE_PRICING] Gift Card - Tax calculations", () => refundable: 50000, tax_lines: expect.arrayContaining([ expect.objectContaining({ - rate: 19 - }) + rate: 19, + }), ]), - }) + }), ]), - }), + }) ) }) }) diff --git a/integration-tests/api/__tests__/store/orders.js b/integration-tests/api/__tests__/store/orders.js index 686d6ab657..9e5373006a 100644 --- a/integration-tests/api/__tests__/store/orders.js +++ b/integration-tests/api/__tests__/store/orders.js @@ -67,7 +67,9 @@ describe("/store/carts", () => { }) const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfile.default, + }, }) await manager.insert(Product, { id: "test-product", @@ -313,7 +315,7 @@ describe("/store/carts", () => { MedusaError.Codes.INSUFFICIENT_INVENTORY ) - let payments = await manager.find(Payment, { cart_id: cartId }) + let payments = await manager.find(Payment, { where: { cart_id: cartId } }) expect(payments).toHaveLength(1) expect(payments).toContainEqual( expect.objectContaining({ @@ -338,7 +340,7 @@ describe("/store/carts", () => { expect(responseSuccess.status).toEqual(200) expect(responseSuccess.data.type).toEqual("order") - payments = await manager.find(Payment, { cart_id: cartId }) + payments = await manager.find(Payment, { where: { cart_id: cartId } }) expect(payments).toHaveLength(2) expect(payments).toEqual( expect.arrayContaining([ @@ -391,7 +393,9 @@ describe("/store/carts", () => { expect(responseSuccess.status).toEqual(200) expect(responseSuccess.data.type).toEqual("order") - const payments = await manager.find(Payment, { cart_id: cartId }) + const payments = await manager.find(Payment, { + where: { cart_id: cartId }, + }) expect(payments).toHaveLength(1) expect(payments).toContainEqual( expect.objectContaining({ diff --git a/integration-tests/api/__tests__/store/returns.js b/integration-tests/api/__tests__/store/returns.js index 95171283ea..6b11fcc227 100644 --- a/integration-tests/api/__tests__/store/returns.js +++ b/integration-tests/api/__tests__/store/returns.js @@ -48,7 +48,9 @@ describe("/store/carts", () => { ) const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfile.default, + }, }) await manager.insert(Region, { diff --git a/integration-tests/api/__tests__/store/shipping-options.js b/integration-tests/api/__tests__/store/shipping-options.js index c9ee7c5c46..d9b70310c8 100644 --- a/integration-tests/api/__tests__/store/shipping-options.js +++ b/integration-tests/api/__tests__/store/shipping-options.js @@ -1,5 +1,10 @@ const path = require("path") -const { Region, ShippingProfile, ShippingOption } = require("@medusajs/medusa") +const { + Region, + ShippingProfile, + ShippingOption, + ShippingProfileType, +} = require("@medusajs/medusa") const setupServer = require("../../../helpers/setup-server") const { useApi } = require("../../../helpers/use-api") @@ -60,7 +65,9 @@ describe("/store/shipping-options", () => { }) const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfileType.DEFAULT, + }, }) await manager.insert(ShippingOption, { diff --git a/integration-tests/api/__tests__/store/swaps.js b/integration-tests/api/__tests__/store/swaps.js index e8f80b62f4..43eb467eb6 100644 --- a/integration-tests/api/__tests__/store/swaps.js +++ b/integration-tests/api/__tests__/store/swaps.js @@ -1,5 +1,9 @@ const path = require("path") -const { ShippingProfile, ShippingOption } = require("@medusajs/medusa") +const { + ShippingProfile, + ShippingOption, + ShippingProfileType, +} = require("@medusajs/medusa") const setupServer = require("../../../helpers/setup-server") const { useApi } = require("../../../helpers/use-api") @@ -38,7 +42,9 @@ describe("/store/carts", () => { ) const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfileType.DEFAULT, + }, }) await manager.insert(ShippingOption, { id: "return-option", diff --git a/integration-tests/api/factories/simple-address-factory.ts b/integration-tests/api/factories/simple-address-factory.ts index cb40d162d8..fbf51395d9 100644 --- a/integration-tests/api/factories/simple-address-factory.ts +++ b/integration-tests/api/factories/simple-address-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { Address } from "@medusajs/medusa" @@ -11,7 +11,7 @@ export type AddressFactoryData = { } export const simpleAddressFactory = async ( - connection: Connection, + dataSource: DataSource, data: AddressFactoryData = {}, seed?: number ): Promise
=> { @@ -19,7 +19,7 @@ export const simpleAddressFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const address = manager.create(Address, { id: `simple-id-${Math.random() * 1000}`, diff --git a/integration-tests/api/factories/simple-analytics-config-factory.ts b/integration-tests/api/factories/simple-analytics-config-factory.ts index 4512d87311..64d0783761 100644 --- a/integration-tests/api/factories/simple-analytics-config-factory.ts +++ b/integration-tests/api/factories/simple-analytics-config-factory.ts @@ -1,5 +1,5 @@ import { AnalyticsConfig } from "@medusajs/medusa" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" export type AnalyticsConfigData = { id?: string @@ -9,10 +9,10 @@ export type AnalyticsConfigData = { } export const simpleAnalyticsConfigFactory = async ( - connection: Connection, + dataSource: DataSource, data: AnalyticsConfigData = {} ): Promise => { - const manager = connection.manager + const manager = dataSource.manager const job = manager.create(AnalyticsConfig, { id: data.id ?? "test-analytics-config", diff --git a/integration-tests/api/factories/simple-batch-job-factory.ts b/integration-tests/api/factories/simple-batch-job-factory.ts index d4a61647d7..c037777baf 100644 --- a/integration-tests/api/factories/simple-batch-job-factory.ts +++ b/integration-tests/api/factories/simple-batch-job-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { BatchJob, BatchJobStatus } from "@medusajs/medusa" export type BatchJobFactoryData = { @@ -12,10 +12,10 @@ export type BatchJobFactoryData = { } export const simpleBatchJobFactory = async ( - connection: Connection, + dataSource: DataSource, data: BatchJobFactoryData = {} ): Promise => { - const manager = connection.manager + const manager = dataSource.manager const job = manager.create(BatchJob, { id: data.id, diff --git a/integration-tests/api/factories/simple-cart-factory.ts b/integration-tests/api/factories/simple-cart-factory.ts index 742d4c84b4..40d038f893 100644 --- a/integration-tests/api/factories/simple-cart-factory.ts +++ b/integration-tests/api/factories/simple-cart-factory.ts @@ -1,6 +1,6 @@ import { Cart } from "@medusajs/medusa" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { AddressFactoryData, simpleAddressFactory, @@ -32,7 +32,7 @@ export type CartFactoryData = { } export const simpleCartFactory = async ( - connection: Connection, + dataSource: DataSource, data: CartFactoryData = {}, seed?: number ): Promise => { @@ -40,37 +40,37 @@ export const simpleCartFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager let regionId: string if (typeof data.region === "string") { regionId = data.region } else { - const region = await simpleRegionFactory(connection, data.region) + const region = await simpleRegionFactory(dataSource, data.region) regionId = region.id } - let customerId: string + let customerId!: string if (typeof data.customer === "string") { customerId = data.customer } else { if (data?.customer?.email) { - const customer = await simpleCustomerFactory(connection, data.customer) + const customer = await simpleCustomerFactory(dataSource, data.customer) customerId = customer.id } else if (data.email) { - const customer = await simpleCustomerFactory(connection, { + const customer = await simpleCustomerFactory(dataSource, { email: data.email, }) customerId = customer.id } } - const address = await simpleAddressFactory(connection, data.shipping_address) + const address = await simpleAddressFactory(dataSource, data.shipping_address) let sales_channel if (typeof data.sales_channel !== "undefined") { sales_channel = await simpleSalesChannelFactory( - connection, + dataSource, data.sales_channel ) } @@ -90,12 +90,12 @@ export const simpleCartFactory = async ( const shippingMethods = data.shipping_methods || [] for (const sm of shippingMethods) { - await simpleShippingMethodFactory(connection, { ...sm, cart_id: id }) + await simpleShippingMethodFactory(dataSource, { ...sm, cart_id: id }) } const items = data.line_items || [] for (const item of items) { - await simpleLineItemFactory(connection, { ...item, cart_id: id }) + await simpleLineItemFactory(dataSource, { ...item, cart_id: id }) } return cart diff --git a/integration-tests/api/factories/simple-custom-shipping-option-factory.ts b/integration-tests/api/factories/simple-custom-shipping-option-factory.ts index f3404bbfe0..0c139d4897 100644 --- a/integration-tests/api/factories/simple-custom-shipping-option-factory.ts +++ b/integration-tests/api/factories/simple-custom-shipping-option-factory.ts @@ -1,8 +1,6 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" -import { - CustomShippingOption, -} from "@medusajs/medusa" +import { CustomShippingOption } from "@medusajs/medusa" export type CustomShippingOptionFactoryData = { id?: string @@ -13,7 +11,7 @@ export type CustomShippingOptionFactoryData = { } export const simpleCustomShippingOptionFactory = async ( - connection: Connection, + dataSource: DataSource, data: CustomShippingOptionFactoryData, seed?: number ): Promise => { @@ -21,14 +19,14 @@ export const simpleCustomShippingOptionFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const customShippingOptionData = { id: data.id ?? `custon-simple-so-${Math.random() * 1000}`, price: typeof data.price !== "undefined" ? data.price : 500, cart_id: data.cart_id, shipping_option_id: data.shipping_option_id, - metadata: data.metadata ?? {} + metadata: data.metadata ?? {}, } const created = manager.create(CustomShippingOption, customShippingOptionData) diff --git a/integration-tests/api/factories/simple-customer-factory.ts b/integration-tests/api/factories/simple-customer-factory.ts index 7c06e5d7e7..b4ab8875bf 100644 --- a/integration-tests/api/factories/simple-customer-factory.ts +++ b/integration-tests/api/factories/simple-customer-factory.ts @@ -1,10 +1,7 @@ import faker from "faker" -import { Customer } from "@medusajs/medusa" -import { Connection } from "typeorm" -import { - CustomerGroupFactoryData, - simpleCustomerGroupFactory, -} from "./simple-customer-group-factory" +import { DataSource } from "typeorm" +import { Customer, CustomerGroup } from "@medusajs/medusa" +import { CustomerGroupFactoryData, simpleCustomerGroupFactory, } from "./simple-customer-group-factory" export type CustomerFactoryData = { id?: string @@ -18,7 +15,7 @@ export type CustomerFactoryData = { } export const simpleCustomerFactory = async ( - connection: Connection, + dataSource: DataSource, data: CustomerFactoryData = {}, seed?: number ): Promise => { @@ -26,7 +23,7 @@ export const simpleCustomerFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const customerId = data.id || `simple-customer-${Math.random() * 1000}` const c = manager.create(Customer, { @@ -49,9 +46,9 @@ export const simpleCustomerFactory = async ( const customer = await manager.save(c) if (data.groups) { - const groups = [] + const groups: CustomerGroup[] = [] for (const g of data.groups) { - const created = await simpleCustomerGroupFactory(connection, g) + const created = await simpleCustomerGroupFactory(dataSource, g) groups.push(created) } diff --git a/integration-tests/api/factories/simple-customer-group-factory.ts b/integration-tests/api/factories/simple-customer-group-factory.ts index 4d4f85a168..53cfe642f7 100644 --- a/integration-tests/api/factories/simple-customer-group-factory.ts +++ b/integration-tests/api/factories/simple-customer-group-factory.ts @@ -1,6 +1,6 @@ import { CustomerGroup } from "@medusajs/medusa" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" export type CustomerGroupFactoryData = { id?: string @@ -8,7 +8,7 @@ export type CustomerGroupFactoryData = { } export const simpleCustomerGroupFactory = async ( - connection: Connection, + dataSource: DataSource, data: CustomerGroupFactoryData = {}, seed?: number ): Promise => { @@ -16,7 +16,7 @@ export const simpleCustomerGroupFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const customerGroupId = data.id || `simple-customer-group-${Math.random() * 1000}` diff --git a/integration-tests/api/factories/simple-discount-condition-factory.ts b/integration-tests/api/factories/simple-discount-condition-factory.ts index eba3af4a27..0a4bfb7dcc 100644 --- a/integration-tests/api/factories/simple-discount-condition-factory.ts +++ b/integration-tests/api/factories/simple-discount-condition-factory.ts @@ -10,7 +10,7 @@ import { DiscountConditionProductTag } from "@medusajs/medusa/dist/models/discou import { DiscountConditionProductType } from "@medusajs/medusa/dist/models/discount-condition-product-type" import { DiscountConditionJoinTableForeignKey } from "@medusajs/medusa/dist/repositories/discount-condition" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" export type DiscountConditionFactoryData = { id?: string @@ -66,7 +66,7 @@ const getJoinTableResourceIdentifiers = (type: string) => { } export const simpleDiscountConditionFactory = async ( - connection: Connection, + dataSource: DataSource, data: DiscountConditionFactoryData, seed?: number ): Promise => { @@ -74,7 +74,7 @@ export const simpleDiscountConditionFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager let resources = [] diff --git a/integration-tests/api/factories/simple-discount-factory.ts b/integration-tests/api/factories/simple-discount-factory.ts index f8e88eea43..8495c3038b 100644 --- a/integration-tests/api/factories/simple-discount-factory.ts +++ b/integration-tests/api/factories/simple-discount-factory.ts @@ -2,13 +2,13 @@ import { AllocationType, Discount, DiscountRule, - DiscountRuleType + DiscountRuleType, } from "@medusajs/medusa" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { DiscountConditionFactoryData, - simpleDiscountConditionFactory + simpleDiscountConditionFactory, } from "./simple-discount-condition-factory" export type DiscountRuleFactoryData = { @@ -29,7 +29,7 @@ export type DiscountFactoryData = { } export const simpleDiscountFactory = async ( - connection: Connection, + dataSource: DataSource, data: DiscountFactoryData = {}, seed?: number ): Promise => { @@ -37,7 +37,7 @@ export const simpleDiscountFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const ruleData = data.rule ?? ({} as DiscountRuleFactoryData) const ruleToSave = manager.create(DiscountRule, { @@ -51,7 +51,7 @@ export const simpleDiscountFactory = async ( if (data?.rule?.conditions) { for (const condition of data.rule.conditions) { await simpleDiscountConditionFactory( - connection, + dataSource, { ...condition, rule_id: dRule.id }, 1 ) diff --git a/integration-tests/api/factories/simple-gift-card-factory.ts b/integration-tests/api/factories/simple-gift-card-factory.ts index 0baaf2b1c5..05d5fa9755 100644 --- a/integration-tests/api/factories/simple-gift-card-factory.ts +++ b/integration-tests/api/factories/simple-gift-card-factory.ts @@ -1,6 +1,6 @@ import { GiftCard } from "@medusajs/medusa" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" export type GiftCardFactoryData = { id?: string @@ -12,7 +12,7 @@ export type GiftCardFactoryData = { } export const simpleGiftCardFactory = async ( - connection: Connection, + dataSource: DataSource, data: GiftCardFactoryData, seed?: number ): Promise => { @@ -20,7 +20,7 @@ export const simpleGiftCardFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const toSave = manager.create(GiftCard, { id: data.id, diff --git a/integration-tests/api/factories/simple-line-item-factory.ts b/integration-tests/api/factories/simple-line-item-factory.ts index fbae1a2f15..ef45a333f9 100644 --- a/integration-tests/api/factories/simple-line-item-factory.ts +++ b/integration-tests/api/factories/simple-line-item-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { LineItem, LineItemAdjustment, LineItemTaxLine } from "@medusajs/medusa" @@ -36,7 +36,7 @@ export type LineItemFactoryData = { } export const simpleLineItemFactory = async ( - connection: Connection, + dataSource: DataSource, data: LineItemFactoryData, seed?: number ): Promise => { @@ -52,7 +52,7 @@ export const simpleLineItemFactory = async ( Math } - const manager = connection.manager + const manager = dataSource.manager const id = data.id || `simple-line-${Math.random() * 1000}` const toSave = manager.create(LineItem, { diff --git a/integration-tests/api/factories/simple-order-edit-factory.ts b/integration-tests/api/factories/simple-order-edit-factory.ts index 64d1ef2777..842d529358 100644 --- a/integration-tests/api/factories/simple-order-edit-factory.ts +++ b/integration-tests/api/factories/simple-order-edit-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { OrderFactoryData, simpleOrderFactory } from "./simple-order-factory" import { OrderEdit } from "@medusajs/medusa" @@ -22,13 +22,13 @@ export type OrderEditFactoryData = { } export const simpleOrderEditFactory = async ( - connection: Connection, + dataSource: DataSource, data: OrderEditFactoryData = {} ): Promise => { - const manager = connection.manager + const manager = dataSource.manager if (!data.order_id) { - const order = await simpleOrderFactory(connection, data.order) + const order = await simpleOrderFactory(dataSource, data.order) data.order_id = order.id } diff --git a/integration-tests/api/factories/simple-order-factory.ts b/integration-tests/api/factories/simple-order-factory.ts index 8450e09484..66e549da94 100644 --- a/integration-tests/api/factories/simple-order-factory.ts +++ b/integration-tests/api/factories/simple-order-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { Discount, @@ -51,7 +51,7 @@ export type OrderFactoryData = { } export const simpleOrderFactory = async ( - connection: Connection, + dataSource: DataSource, data: OrderFactoryData = {} as OrderFactoryData, seed?: number ): Promise => { @@ -59,7 +59,7 @@ export const simpleOrderFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager let currencyCode: string let regionId: string @@ -70,16 +70,16 @@ export const simpleOrderFactory = async ( regionId = data.region taxRate = data.tax_rate as number } else { - const region = await simpleRegionFactory(connection, data.region) + const region = await simpleRegionFactory(dataSource, data.region) taxRate = (typeof data.tax_rate !== "undefined" ? data.tax_rate : region.tax_rate) as number currencyCode = region.currency_code regionId = region.id } - const address = await simpleAddressFactory(connection, data.shipping_address) + const address = await simpleAddressFactory(dataSource, data.shipping_address) - const customer = await simpleCustomerFactory(connection, { + const customer = await simpleCustomerFactory(dataSource, { ...data.customer, email: data.email ?? undefined, }) @@ -87,14 +87,14 @@ export const simpleOrderFactory = async ( let discounts: Discount[] = [] if (typeof data.discounts !== "undefined") { discounts = await Promise.all( - data.discounts.map((d) => simpleDiscountFactory(connection, d, seed)) + data.discounts.map((d) => simpleDiscountFactory(dataSource, d, seed)) ) } let sales_channel if (typeof data.sales_channel !== "undefined") { sales_channel = await simpleSalesChannelFactory( - connection, + dataSource, data.sales_channel ) } @@ -120,7 +120,7 @@ export const simpleOrderFactory = async ( const shippingMethods = data.shipping_methods || [] for (const sm of shippingMethods) { - await simpleShippingMethodFactory(connection, { ...sm, order_id: order.id }) + await simpleShippingMethodFactory(dataSource, { ...sm, order_id: order.id }) } const items = @@ -136,7 +136,7 @@ export const simpleOrderFactory = async ( }) || [] for (const item of items) { - await simpleLineItemFactory(connection, { ...item, order_id: id } as unknown as LineItemFactoryData) + await simpleLineItemFactory(dataSource, { ...item, order_id: id } as unknown as LineItemFactoryData) } return order diff --git a/integration-tests/api/factories/simple-order-item-change-factory.ts b/integration-tests/api/factories/simple-order-item-change-factory.ts index 99ae72568d..13760896fa 100644 --- a/integration-tests/api/factories/simple-order-item-change-factory.ts +++ b/integration-tests/api/factories/simple-order-item-change-factory.ts @@ -1,9 +1,5 @@ -import { - OrderEdit, - OrderEditItemChangeType, - OrderItemChange, -} from "@medusajs/medusa" -import { Connection } from "typeorm" +import { OrderEditItemChangeType, OrderItemChange } from "@medusajs/medusa" +import { DataSource } from "typeorm" type OrderItemChangeData = { id: string @@ -14,10 +10,10 @@ type OrderItemChangeData = { } export const simpleOrderItemChangeFactory = async ( - connection: Connection, + dataSource: DataSource, data: OrderItemChangeData ) => { - const manager = connection.manager + const manager = dataSource.manager const change = manager.create(OrderItemChange, { id: data.id, type: data.type, diff --git a/integration-tests/api/factories/simple-payment-collection-factory.ts b/integration-tests/api/factories/simple-payment-collection-factory.ts index 599f53b3ba..048a207757 100644 --- a/integration-tests/api/factories/simple-payment-collection-factory.ts +++ b/integration-tests/api/factories/simple-payment-collection-factory.ts @@ -1,14 +1,14 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { simpleRegionFactory } from "./simple-region-factory" import { simplePaymentFactory } from "./simple-payment-factory" import { Payment, PaymentCollection } from "@medusajs/medusa" export const simplePaymentCollectionFactory = async ( - connection: Connection, + dataSource: DataSource, data: Partial = {} ): Promise => { - const manager = connection.manager + const manager = dataSource.manager const defaultData = { currency_code: data.currency_code ?? "usd", @@ -19,7 +19,7 @@ export const simplePaymentCollectionFactory = async ( } if (!data.region && !data.region_id) { - data.region = await simpleRegionFactory(connection, { + data.region = await simpleRegionFactory(dataSource, { id: data.region_id || "test-region", currency_code: defaultData.currency_code, }) @@ -32,7 +32,7 @@ export const simplePaymentCollectionFactory = async ( payment.currency_code = payment.currency_code ?? defaultData.currency_code const savedPayment = await simplePaymentFactory( - connection, + dataSource, payment as any ) payments.push(savedPayment) diff --git a/integration-tests/api/factories/simple-payment-factory.ts b/integration-tests/api/factories/simple-payment-factory.ts index 2c56236438..5673368f08 100644 --- a/integration-tests/api/factories/simple-payment-factory.ts +++ b/integration-tests/api/factories/simple-payment-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { Payment } from "@medusajs/medusa" export type PaymentFactoryData = { @@ -12,11 +12,11 @@ export type PaymentFactoryData = { } export const simplePaymentFactory = async ( - connection: Connection, + dataSource: DataSource, data: PaymentFactoryData, _?: number ): Promise => { - const manager = connection.manager + const manager = dataSource.manager let captured_at = data.captured if (typeof captured_at === "boolean") { diff --git a/integration-tests/api/factories/simple-price-list-factory.ts b/integration-tests/api/factories/simple-price-list-factory.ts index a9cc0693ac..2a0000edd3 100644 --- a/integration-tests/api/factories/simple-price-list-factory.ts +++ b/integration-tests/api/factories/simple-price-list-factory.ts @@ -6,7 +6,7 @@ import { PriceListType, } from "@medusajs/medusa" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { simpleCustomerGroupFactory } from "./simple-customer-group-factory" type ProductListPrice = { @@ -30,7 +30,7 @@ export type PriceListFactoryData = { } export const simplePriceListFactory = async ( - connection: Connection, + dataSource: DataSource, data: PriceListFactoryData = {}, seed?: number ): Promise => { @@ -38,7 +38,7 @@ export const simplePriceListFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const listId = data.id || `simple-price-list-${Math.random() * 1000}` @@ -46,7 +46,7 @@ export const simplePriceListFactory = async ( if (typeof data.customer_groups !== "undefined") { customerGroups = await Promise.all( data.customer_groups.map((group) => - simpleCustomerGroupFactory(connection, { id: group }) + simpleCustomerGroupFactory(dataSource, { id: group }) ) ) } diff --git a/integration-tests/api/factories/simple-product-category-factory.ts b/integration-tests/api/factories/simple-product-category-factory.ts index fa68f19720..be9df1a6a5 100644 --- a/integration-tests/api/factories/simple-product-category-factory.ts +++ b/integration-tests/api/factories/simple-product-category-factory.ts @@ -1,12 +1,12 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { ProductCategory } from "@medusajs/medusa" export const simpleProductCategoryFactory = async ( - connection: Connection, + dataSource: DataSource, data: Partial = {} ): Promise => { - const manager = connection.manager - const category = manager.create(ProductCategory, data) + const manager = dataSource.manager + const productCategory = manager.create(ProductCategory, data) - return await manager.save(category) + return await manager.save(productCategory) } diff --git a/integration-tests/api/factories/simple-product-collection-factory.ts b/integration-tests/api/factories/simple-product-collection-factory.ts index e950417980..78c8a6e268 100644 --- a/integration-tests/api/factories/simple-product-collection-factory.ts +++ b/integration-tests/api/factories/simple-product-collection-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { ProductCollection } from "@medusajs/medusa" @@ -11,7 +11,7 @@ export const simpleProductCollectionFactory = async < TData extends Data | Data[] = Data | Data[], TResult = TData extends Array ? ProductCollection[] : ProductCollection >( - connection: Connection, + dataSource: DataSource, data?: TData, seed?: number ): Promise => { @@ -19,7 +19,7 @@ export const simpleProductCollectionFactory = async < faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager data = data || [{ title: faker.datatype.string(10), diff --git a/integration-tests/api/factories/simple-product-factory.ts b/integration-tests/api/factories/simple-product-factory.ts index aaece4f022..9e39af8528 100644 --- a/integration-tests/api/factories/simple-product-factory.ts +++ b/integration-tests/api/factories/simple-product-factory.ts @@ -8,7 +8,7 @@ import { Store, } from "@medusajs/medusa" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { ProductVariantFactoryData, simpleProductVariantFactory, @@ -32,22 +32,26 @@ export type ProductFactoryData = { } export const simpleProductFactory = async ( - connection: Connection, + dataSource: DataSource, data: ProductFactoryData = {}, seed?: number -): Promise => { +): Promise => { if (typeof seed !== "undefined") { faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: ShippingProfileType.DEFAULT, + where: { + type: ShippingProfileType.DEFAULT, + } }) const gcProfile = await manager.findOne(ShippingProfile, { - type: ShippingProfileType.GIFT_CARD, + where: { + type: ShippingProfileType.GIFT_CARD, + } }) let sales_channels @@ -55,18 +59,20 @@ export const simpleProductFactory = async ( sales_channels = await Promise.all( data.sales_channels.map( async (salesChannel) => - await simpleSalesChannelFactory(connection, salesChannel) + await simpleSalesChannelFactory(dataSource, salesChannel) ) ) } else { - const store = await manager.findOne(Store, { - relations: ["default_sales_channel"], + const stores = await manager.find(Store, { + relations: { default_sales_channel: true }, }) + const store = stores[0] + if (store?.default_sales_channel) { sales_channels = [store.default_sales_channel] } else { - const salesChannel = await simpleSalesChannelFactory(connection, { + const salesChannel = await simpleSalesChannelFactory(dataSource, { id: `default-${Math.random() * 1000}`, is_default: true, }) @@ -144,12 +150,16 @@ export const simpleProductFactory = async ( { option_id: optionId, value: faker.commerce.productAdjective() }, ] } - await simpleProductVariantFactory(connection, factoryData) + await simpleProductVariantFactory(dataSource, factoryData) } return await manager.findOne( Product, - { id: prodId }, - { relations: ["tags", "variants", "variants.prices"] } + { + where: { + id: prodId + }, + relations: { tags: true, variants: { prices: true }} + } ) } diff --git a/integration-tests/api/factories/simple-product-tax-rate-factory.ts b/integration-tests/api/factories/simple-product-tax-rate-factory.ts index 4b731c51b3..6b3078f382 100644 --- a/integration-tests/api/factories/simple-product-tax-rate-factory.ts +++ b/integration-tests/api/factories/simple-product-tax-rate-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { ProductTaxRate, TaxRate } from "@medusajs/medusa" @@ -15,7 +15,7 @@ export type ProductTaxRateFactoryData = { } export const simpleProductTaxRateFactory = async ( - connection: Connection, + dataSource: DataSource, data: ProductTaxRateFactoryData, seed?: number ): Promise => { @@ -23,7 +23,7 @@ export const simpleProductTaxRateFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager let rateId: string if (typeof data.rate === "string") { diff --git a/integration-tests/api/factories/simple-product-type-tax-rate-factory.ts b/integration-tests/api/factories/simple-product-type-tax-rate-factory.ts index 47402a6cbf..ec64c945fe 100644 --- a/integration-tests/api/factories/simple-product-type-tax-rate-factory.ts +++ b/integration-tests/api/factories/simple-product-type-tax-rate-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { ProductTypeTaxRate, TaxRate } from "@medusajs/medusa" @@ -15,7 +15,7 @@ export type ProductTypeTaxRateFactoryData = { } export const simpleProductTypeTaxRateFactory = async ( - connection: Connection, + dataSource: DataSource, data: ProductTypeTaxRateFactoryData, seed?: number ): Promise => { @@ -23,7 +23,7 @@ export const simpleProductTypeTaxRateFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager let rateId: string if (typeof data.rate === "string") { diff --git a/integration-tests/api/factories/simple-product-variant-factory.ts b/integration-tests/api/factories/simple-product-variant-factory.ts index f203ed7516..25c43ee5b7 100644 --- a/integration-tests/api/factories/simple-product-variant-factory.ts +++ b/integration-tests/api/factories/simple-product-variant-factory.ts @@ -1,9 +1,9 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { + MoneyAmount, ProductOptionValue, ProductVariant, - MoneyAmount, } from "@medusajs/medusa" export type ProductVariantFactoryData = { @@ -18,7 +18,7 @@ export type ProductVariantFactoryData = { } export const simpleProductVariantFactory = async ( - connection: Connection, + dataSource: DataSource, data: ProductVariantFactoryData, seed?: number ): Promise => { @@ -26,7 +26,7 @@ export const simpleProductVariantFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const id = data.id || `simple-variant-${Math.random() * 1000}` const toSave = manager.create(ProductVariant, { diff --git a/integration-tests/api/factories/simple-publishable-api-key-factory.ts b/integration-tests/api/factories/simple-publishable-api-key-factory.ts index 048d64d6d4..3271da7fb4 100644 --- a/integration-tests/api/factories/simple-publishable-api-key-factory.ts +++ b/integration-tests/api/factories/simple-publishable-api-key-factory.ts @@ -1,5 +1,5 @@ import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { PublishableApiKey } from "@medusajs/medusa" @@ -12,10 +12,10 @@ export type PublishableApiKeyData = { } export const simplePublishableApiKeyFactory = async ( - connection: Connection, + dataSource: DataSource, data: PublishableApiKeyData = {} ): Promise => { - const manager = connection.manager + const manager = dataSource.manager const pubKey = manager.create(PublishableApiKey, { ...data, diff --git a/integration-tests/api/factories/simple-region-factory.ts b/integration-tests/api/factories/simple-region-factory.ts index 6a473b681e..b28517bb4c 100644 --- a/integration-tests/api/factories/simple-region-factory.ts +++ b/integration-tests/api/factories/simple-region-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { Region } from "@medusajs/medusa" @@ -15,7 +15,7 @@ export type RegionFactoryData = { } export const simpleRegionFactory = async ( - connection: Connection, + dataSource: DataSource, data: RegionFactoryData = {}, seed?: number ): Promise => { @@ -23,7 +23,7 @@ export const simpleRegionFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const regionId = data.id || `simple-region-${Math.random() * 1000}` const r = manager.create(Region, { diff --git a/integration-tests/api/factories/simple-sales-channel-factory.ts b/integration-tests/api/factories/simple-sales-channel-factory.ts index 095efc7c8e..69b2992563 100644 --- a/integration-tests/api/factories/simple-sales-channel-factory.ts +++ b/integration-tests/api/factories/simple-sales-channel-factory.ts @@ -1,18 +1,18 @@ import { Product, SalesChannel } from "@medusajs/medusa" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" export type SalesChannelFactoryData = { name?: string description?: string is_disabled?: boolean id?: string - products?: Product[], + products?: Product[] is_default?: boolean } export const simpleSalesChannelFactory = async ( - connection: Connection, + dataSource: DataSource, data: SalesChannelFactoryData = {}, seed?: number ): Promise => { @@ -20,7 +20,7 @@ export const simpleSalesChannelFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager let salesChannel = manager.create(SalesChannel, { id: data.id ?? `simple-id-${Math.random() * 1000}`, diff --git a/integration-tests/api/factories/simple-shipping-method-factory.ts b/integration-tests/api/factories/simple-shipping-method-factory.ts index ef219f45ab..20ce58bcaa 100644 --- a/integration-tests/api/factories/simple-shipping-method-factory.ts +++ b/integration-tests/api/factories/simple-shipping-method-factory.ts @@ -1,6 +1,6 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" -import { ShippingMethodTaxLine, ShippingMethod } from "@medusajs/medusa" +import { ShippingMethod, ShippingMethodTaxLine } from "@medusajs/medusa" import { ShippingOptionFactoryData, @@ -19,7 +19,7 @@ export type ShippingMethodFactoryData = { } export const simpleShippingMethodFactory = async ( - connection: Connection, + dataSource: DataSource, data: ShippingMethodFactoryData, seed?: number ): Promise => { @@ -27,14 +27,14 @@ export const simpleShippingMethodFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager let shippingOptionId: string if (typeof data.shipping_option === "string") { shippingOptionId = data.shipping_option } else { const option = await simpleShippingOptionFactory( - connection, + dataSource, data.shipping_option ) shippingOptionId = option.id diff --git a/integration-tests/api/factories/simple-shipping-option-factory.ts b/integration-tests/api/factories/simple-shipping-option-factory.ts index f3462eb0c5..cddfc228ff 100644 --- a/integration-tests/api/factories/simple-shipping-option-factory.ts +++ b/integration-tests/api/factories/simple-shipping-option-factory.ts @@ -6,7 +6,7 @@ import { ShippingProfileType, } from "@medusajs/medusa" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import { simpleRegionFactory } from "./simple-region-factory" export type ShippingOptionFactoryData = { @@ -28,7 +28,7 @@ type ShippingOptionRequirementData = { } export const simpleShippingOptionFactory = async ( - connection: Connection, + dataSource: DataSource, data: ShippingOptionFactoryData = {}, seed?: number ): Promise => { @@ -36,19 +36,23 @@ export const simpleShippingOptionFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: ShippingProfileType.DEFAULT, + where: { + type: ShippingProfileType.DEFAULT, + } }) const gcProfile = await manager.findOne(ShippingProfile, { - type: ShippingProfileType.GIFT_CARD, + where: { + type: ShippingProfileType.GIFT_CARD, + } }) let region_id = data.region_id if (!region_id) { - const { id } = await simpleRegionFactory(connection) + const { id } = await simpleRegionFactory(dataSource) region_id = id } diff --git a/integration-tests/api/factories/simple-shipping-tax-rate-factory.ts b/integration-tests/api/factories/simple-shipping-tax-rate-factory.ts index 1ce21cdda9..c40677ca39 100644 --- a/integration-tests/api/factories/simple-shipping-tax-rate-factory.ts +++ b/integration-tests/api/factories/simple-shipping-tax-rate-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { ShippingTaxRate, TaxRate } from "@medusajs/medusa" @@ -15,7 +15,7 @@ export type ShippingTaxRateFactoryData = { } export const simpleShippingTaxRateFactory = async ( - connection: Connection, + dataSource: DataSource, data: ShippingTaxRateFactoryData, seed?: number ): Promise => { @@ -23,7 +23,7 @@ export const simpleShippingTaxRateFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager let rateId: string if (typeof data.rate === "string") { diff --git a/integration-tests/api/factories/simple-tax-rate-factory.ts b/integration-tests/api/factories/simple-tax-rate-factory.ts index 44987da67e..f2efa356c2 100644 --- a/integration-tests/api/factories/simple-tax-rate-factory.ts +++ b/integration-tests/api/factories/simple-tax-rate-factory.ts @@ -1,4 +1,4 @@ -import { Connection } from "typeorm" +import { DataSource } from "typeorm" import faker from "faker" import { TaxRate } from "@medusajs/medusa" @@ -10,7 +10,7 @@ export type TaxRateFactoryData = { } export const simpleTaxRateFactory = async ( - connection: Connection, + dataSource: DataSource, data: TaxRateFactoryData, seed?: number ): Promise => { @@ -18,7 +18,7 @@ export const simpleTaxRateFactory = async ( faker.seed(seed) } - const manager = connection.manager + const manager = dataSource.manager const toSave = manager.create(TaxRate, { region_id: data.region_id, diff --git a/integration-tests/api/helpers/admin-seeder.js b/integration-tests/api/helpers/admin-seeder.js index 660bad0470..95f63c6326 100644 --- a/integration-tests/api/helpers/admin-seeder.js +++ b/integration-tests/api/helpers/admin-seeder.js @@ -1,8 +1,8 @@ const Scrypt = require("scrypt-kdf") const { User } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const buf = await Scrypt.kdf("secret_password", { logN: 1, r: 1, p: 1 }) const password_hash = buf.toString("base64") diff --git a/integration-tests/api/helpers/admin-variants-seeder.js b/integration-tests/api/helpers/admin-variants-seeder.js index 9c8a82a63a..9245746283 100644 --- a/integration-tests/api/helpers/admin-variants-seeder.js +++ b/integration-tests/api/helpers/admin-variants-seeder.js @@ -11,8 +11,8 @@ const { ProductOption, } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const yesterday = ((today) => new Date(today.setDate(today.getDate() - 1)))( new Date() @@ -23,7 +23,7 @@ module.exports = async (connection, data = {}) => { ) const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { type: ShippingProfile.default }, }) const collection = manager.create(ProductCollection, { diff --git a/integration-tests/api/helpers/batch-job-seeder.js b/integration-tests/api/helpers/batch-job-seeder.js index e05af25e10..7f41c5a52e 100644 --- a/integration-tests/api/helpers/batch-job-seeder.js +++ b/integration-tests/api/helpers/batch-job-seeder.js @@ -1,7 +1,7 @@ const { Region } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager await manager.insert(Region, { id: "region-product-import-0", diff --git a/integration-tests/api/helpers/cart-seeder.js b/integration-tests/api/helpers/cart-seeder.js index 32bc01ccbd..9bfbec1f3d 100644 --- a/integration-tests/api/helpers/cart-seeder.js +++ b/integration-tests/api/helpers/cart-seeder.js @@ -16,9 +16,10 @@ const { PaymentSession, CustomerGroup, PriceList, + ShippingProfileType, } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { +module.exports = async (dataSource, data = {}) => { const yesterday = ((today) => new Date(today.setDate(today.getDate() - 1)))( new Date() ) @@ -31,14 +32,14 @@ module.exports = async (connection, data = {}) => { const tenDaysFromToday = ((today) => new Date(today.setDate(today.getDate() + 10)))(new Date()) - const manager = connection.manager + const manager = dataSource.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { type: ShippingProfileType.DEFAULT }, }) const gcProfile = await manager.findOne(ShippingProfile, { - type: "gift_card", + where: { type: ShippingProfileType.GIFT_CARD }, }) await manager.insert(Address, { diff --git a/integration-tests/api/helpers/claim-seeder.js b/integration-tests/api/helpers/claim-seeder.js index ae19e09e68..abeeb045d5 100644 --- a/integration-tests/api/helpers/claim-seeder.js +++ b/integration-tests/api/helpers/claim-seeder.js @@ -6,8 +6,8 @@ const { Return, } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager let orderWithClaim = manager.create(Order, { id: "order-with-claim", diff --git a/integration-tests/api/helpers/customer-seeder.js b/integration-tests/api/helpers/customer-seeder.js index 0c10e0a2c5..fe6085f47b 100644 --- a/integration-tests/api/helpers/customer-seeder.js +++ b/integration-tests/api/helpers/customer-seeder.js @@ -1,7 +1,7 @@ const { Customer, Address, CustomerGroup } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const testAddr = await manager.create(Address, { id: "test-address", diff --git a/integration-tests/api/helpers/discount-seeder.js b/integration-tests/api/helpers/discount-seeder.js index cc623bab33..26c7ebf842 100644 --- a/integration-tests/api/helpers/discount-seeder.js +++ b/integration-tests/api/helpers/discount-seeder.js @@ -4,8 +4,8 @@ const { Discount, DiscountRule, } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager await manager.insert(Region, { id: "test-region", diff --git a/integration-tests/api/helpers/draft-order-seeder.js b/integration-tests/api/helpers/draft-order-seeder.js index 83c9a45647..c1749dcffc 100644 --- a/integration-tests/api/helpers/draft-order-seeder.js +++ b/integration-tests/api/helpers/draft-order-seeder.js @@ -14,17 +14,18 @@ const { Discount, DiscountRule, Payment, + ShippingProfileType, } = require("@medusajs/medusa") const { simpleSalesChannelFactory } = require("../factories") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { type: ShippingProfileType.DEFAULT }, }) - const salesChannel = await simpleSalesChannelFactory(connection, { + const salesChannel = await simpleSalesChannelFactory(dataSource, { id: "sales-channel", is_default: true, }) diff --git a/integration-tests/api/helpers/order-seeder.js b/integration-tests/api/helpers/order-seeder.js index f3e5d5d9b5..5f1ca7c9c5 100644 --- a/integration-tests/api/helpers/order-seeder.js +++ b/integration-tests/api/helpers/order-seeder.js @@ -13,17 +13,18 @@ const { ShippingOption, ShippingProfile, Swap, + ShippingProfileType, } = require("@medusajs/medusa") const { simpleSalesChannelFactory } = require("../factories") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { type: ShippingProfileType.DEFAULT }, }) - const salesChannel = await simpleSalesChannelFactory(connection, { + const salesChannel = await simpleSalesChannelFactory(dataSource, { id: "test-channel", is_default: true, }) diff --git a/integration-tests/api/helpers/price-list-seeder.js b/integration-tests/api/helpers/price-list-seeder.js index f481176cc3..8c97092de5 100644 --- a/integration-tests/api/helpers/price-list-seeder.js +++ b/integration-tests/api/helpers/price-list-seeder.js @@ -1,7 +1,7 @@ const { Region, PriceList, MoneyAmount } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const priceListNoCustomerGroups = await manager.create(PriceList, { id: "pl_no_customer_groups", diff --git a/integration-tests/api/helpers/price-selection-seeder.js b/integration-tests/api/helpers/price-selection-seeder.js index 00d939f760..6d3f7d2599 100644 --- a/integration-tests/api/helpers/price-selection-seeder.js +++ b/integration-tests/api/helpers/price-selection-seeder.js @@ -9,9 +9,10 @@ const { Region, Cart, PriceList, + ShippingProfileType, } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { +module.exports = async (dataSource, data = {}) => { const yesterday = ((today) => new Date(today.setDate(today.getDate() - 1)))( new Date() ) @@ -24,10 +25,10 @@ module.exports = async (connection, data = {}) => { const tenDaysFromToday = ((today) => new Date(today.setDate(today.getDate() + 10)))(new Date()) - const manager = connection.manager + const manager = dataSource.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { type: ShippingProfileType.DEFAULT }, }) await manager.insert(Region, { diff --git a/integration-tests/api/helpers/product-seeder.js b/integration-tests/api/helpers/product-seeder.js index 4e48a48c1b..5d2684724d 100644 --- a/integration-tests/api/helpers/product-seeder.js +++ b/integration-tests/api/helpers/product-seeder.js @@ -8,14 +8,16 @@ const { ShippingProfile, ProductVariant, Image, - Store, + ShippingProfileType, } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfileType.DEFAULT, + }, }) const coll = await manager.create(ProductCollection, { diff --git a/integration-tests/api/helpers/shipping-option-seeder.js b/integration-tests/api/helpers/shipping-option-seeder.js index 33d669ca23..79b9ce6130 100644 --- a/integration-tests/api/helpers/shipping-option-seeder.js +++ b/integration-tests/api/helpers/shipping-option-seeder.js @@ -3,10 +3,11 @@ const { ShippingProfile, ShippingOption, ShippingOptionRequirement, + ShippingProfileType, } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager await manager.insert(Region, { id: "region", @@ -16,7 +17,7 @@ module.exports = async (connection, data = {}) => { }) const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { type: ShippingProfileType.DEFAULT }, }) await manager.insert(ShippingOption, { diff --git a/integration-tests/api/helpers/store-product-seeder.js b/integration-tests/api/helpers/store-product-seeder.js index 2290465c1a..adf3973c96 100644 --- a/integration-tests/api/helpers/store-product-seeder.js +++ b/integration-tests/api/helpers/store-product-seeder.js @@ -10,10 +10,11 @@ const { Image, Cart, PriceList, + ShippingProfileType, } = require("@medusajs/medusa") -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const yesterday = ((today) => new Date(today.setDate(today.getDate() - 1)))( new Date() @@ -48,7 +49,7 @@ module.exports = async (connection, data = {}) => { await manager.save(priceList1) const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { type: ShippingProfileType.DEFAULT }, }) const coll = manager.create(ProductCollection, { diff --git a/integration-tests/api/helpers/swap-seeder.js b/integration-tests/api/helpers/swap-seeder.js index 7a93c0f1ce..2ee8b88828 100644 --- a/integration-tests/api/helpers/swap-seeder.js +++ b/integration-tests/api/helpers/swap-seeder.js @@ -16,12 +16,12 @@ const { Region } = require("@medusajs/medusa/dist/models/region") let regionId let region -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager regionId = "test-region" - region = await manager.findOne(Region, { id: regionId }) + region = await manager.findOne(Region, { where: { id: regionId } }) let orderWithSwap = manager.create(Order, { id: "order-with-swap", diff --git a/integration-tests/api/helpers/user-seeder.js b/integration-tests/api/helpers/user-seeder.js index bdea83131c..2724cac368 100644 --- a/integration-tests/api/helpers/user-seeder.js +++ b/integration-tests/api/helpers/user-seeder.js @@ -11,8 +11,8 @@ const expires_at = new Date() expires_at.setDate(expires_at.getDate() + 8) -module.exports = async (connection, data = {}) => { - const manager = connection.manager +module.exports = async (dataSource, data = {}) => { + const manager = dataSource.manager const memberUser = await manager.create(User, { id: "member-user", diff --git a/integration-tests/api/package.json b/integration-tests/api/package.json index 788c34755e..f2f39f27f4 100644 --- a/integration-tests/api/package.json +++ b/integration-tests/api/package.json @@ -12,7 +12,7 @@ "@medusajs/medusa": "*", "faker": "^5.5.3", "medusa-interfaces": "*", - "typeorm": "^0.2.31" + "typeorm": "^0.3.11" }, "devDependencies": { "@babel/cli": "^7.12.10", diff --git a/integration-tests/helpers/use-db.js b/integration-tests/helpers/use-db.js index e64bab03f4..9ab873088c 100644 --- a/integration-tests/helpers/use-db.js +++ b/integration-tests/helpers/use-db.js @@ -2,7 +2,7 @@ const path = require("path") const { getConfigFile } = require("medusa-core-utils") const { dropDatabase } = require("pg-god") -const { createConnection } = require("typeorm") +const { DataSource } = require("typeorm") const dbFactory = require("./use-template-db") const DB_HOST = process.env.DB_HOST @@ -27,13 +27,13 @@ const keepTables = [ "currency", ] -let connectionType = "postgresql" +let dataSourceType = "postgresql" const DbTestUtil = { db_: null, - setDb: function (connection) { - this.db_ = connection + setDb: function (dataSource) { + this.db_ = dataSource }, clear: async function () { @@ -47,7 +47,7 @@ const DbTestUtil = { const manager = this.db_.manager - if (connectionType === "sqlite") { + if (dataSourceType === "sqlite") { await manager.query(`PRAGMA foreign_keys = OFF`) } else { await manager.query(`SET session_replication_role = 'replica';`) @@ -64,7 +64,7 @@ const DbTestUtil = { await manager.query(`DELETE FROM "${entity.tableName}";`) } - if (connectionType === "sqlite") { + if (dataSourceType === "sqlite") { await manager.query(`PRAGMA foreign_keys = ON`) } else { await manager.query(`SET session_replication_role = 'origin';`) @@ -72,7 +72,7 @@ const DbTestUtil = { }, shutdown: async function () { - await this.db_.close() + await this.db_.destroy() return await dropDatabase({ DB_NAME }, pgGodCredentials) }, } @@ -88,14 +88,12 @@ module.exports = { require("@medusajs/medusa/dist/loaders/feature-flags").default const featureFlagsRouter = featureFlagsLoader({ featureFlags }) - const modelsLoader = require("@medusajs/medusa/dist/loaders/models").default - const entities = modelsLoader({}, { register: false }) if (projectConfig.database_type === "sqlite") { - connectionType = "sqlite" - const dbConnection = await createConnection({ + dataSourceType = "sqlite" + const dataSource = new DataSource({ type: "sqlite", database: projectConfig.database_database, synchronize: true, @@ -103,8 +101,10 @@ module.exports = { extra: database_extra ?? {}, }) - instance.setDb(dbConnection) - return dbConnection + const dbDataSource = await dataSource.initialize() + + instance.setDb(dbDataSource) + return dbDataSource } else { await dbFactory.createFromTemplate(DB_NAME) @@ -138,7 +138,7 @@ module.exports = { (e) => typeof e.isFeatureEnabled === "undefined" || e.isFeatureEnabled() ) - const dbConnection = await createConnection({ + const dbDataSource = new DataSource({ type: "postgres", url: DB_URL, entities: enabledEntities.concat(moduleModels), @@ -147,10 +147,12 @@ module.exports = { name: "integration-tests", }) - await dbConnection.runMigrations() + await dbDataSource.initialize() - instance.setDb(dbConnection) - return dbConnection + await dbDataSource.runMigrations() + + instance.setDb(dbDataSource) + return dbDataSource } }, useDb: function () { diff --git a/integration-tests/helpers/use-template-db.js b/integration-tests/helpers/use-template-db.js index 2946c15d46..a20091f6e3 100644 --- a/integration-tests/helpers/use-template-db.js +++ b/integration-tests/helpers/use-template-db.js @@ -4,13 +4,15 @@ require("dotenv").config({ path: path.join(__dirname, "../.env.test") }) const { getConfigFile } = require("medusa-core-utils") const { createDatabase, dropDatabase } = require("pg-god") -const { createConnection, getConnection } = require("typeorm") +const { DataSource } = require("typeorm") const DB_HOST = process.env.DB_HOST const DB_USERNAME = process.env.DB_USERNAME const DB_PASSWORD = process.env.DB_PASSWORD const DB_URL = `postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}` +let masterDataSource + const pgGodCredentials = { user: DB_USERNAME, password: DB_PASSWORD, @@ -19,16 +21,14 @@ const pgGodCredentials = { class DatabaseFactory { constructor() { - this.connection_ = null - this.masterConnectionName = "master" + this.dataSource_ = null + this.masterDataSourceName = "master" this.templateDbName = "medusa-integration-template" } async createTemplateDb_({ cwd }) { const { configModule } = getConfigFile(cwd, `medusa-config`) - - const connection = await this.getMasterConnection() - + const dataSource = await this.getMasterDataSource() const migrationDir = path.resolve( path.join( __dirname, @@ -68,51 +68,52 @@ class DatabaseFactory { pgGodCredentials ) - const templateDbConnection = await createConnection({ + const templateDbDataSource = new DataSource({ type: "postgres", - name: "templateConnection", + name: "templateDataSource", url: `${DB_URL}/${this.templateDbName}`, migrations: enabledMigrations.concat(moduleMigrations), }) - await templateDbConnection.runMigrations() - await templateDbConnection.close() + await templateDbDataSource.initialize() - return connection + await templateDbDataSource.runMigrations() + + await templateDbDataSource.destroy() + + return dataSource } - async getMasterConnection() { - try { - return getConnection(this.masterConnectionName) - } catch (err) { - return await this.createMasterConnection() - } + async getMasterDataSource() { + masterDataSource = masterDataSource || (await this.createMasterDataSource()) + return masterDataSource } - async createMasterConnection() { - const connection = await createConnection({ + async createMasterDataSource() { + const dataSource = new DataSource({ type: "postgres", - name: this.masterConnectionName, + name: this.masterDataSourceName, url: `${DB_URL}`, }) + await dataSource.initialize() - return connection + return dataSource } async createFromTemplate(dbName) { - const connection = await this.getMasterConnection() + const dataSource = await this.getMasterDataSource() - await connection.query(`DROP DATABASE IF EXISTS "${dbName}";`) - await connection.query( + await dataSource.query(`DROP DATABASE IF EXISTS "${dbName}";`) + await dataSource.query( `CREATE DATABASE "${dbName}" TEMPLATE "${this.templateDbName}";` ) } async destroy() { - const connection = await this.getMasterConnection() + const dataSource = await this.getMasterDataSource() - await connection.query(`DROP DATABASE IF EXISTS "${this.templateDbName}";`) - await connection.close() + await dataSource.query(`DROP DATABASE IF EXISTS "${this.templateDbName}";`) + await dataSource.destroy() } } diff --git a/integration-tests/plugins/__tests__/inventory/inventory-items/index.js b/integration-tests/plugins/__tests__/inventory/inventory-items/index.js index 17fad1751a..d29fa8b470 100644 --- a/integration-tests/plugins/__tests__/inventory/inventory-items/index.js +++ b/integration-tests/plugins/__tests__/inventory/inventory-items/index.js @@ -302,7 +302,8 @@ describe("Inventory Items endpoints", () => { const response = await api.get(`/admin/inventory-items`, adminHeaders) - expect(response.data.inventory_items).toEqual([ + expect(response.data.inventory_items).toHaveLength(1) + expect(response.data.inventory_items[0]).toEqual( expect.objectContaining({ id: inventoryItemId, sku: "MY_SKU", @@ -359,8 +360,8 @@ describe("Inventory Items endpoints", () => { available_quantity: 5, }), ]), - }), - ]) + }) + ) }) it("When deleting an inventory item it removes the product variants associated to it", async () => { diff --git a/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap index 186346654c..f5936e289b 100644 --- a/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap +++ b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap @@ -98,6 +98,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -254,6 +255,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -407,6 +409,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -525,6 +528,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -709,6 +713,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -875,6 +880,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -1130,6 +1136,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -1384,6 +1391,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -1598,6 +1606,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -1716,6 +1725,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -1900,6 +1910,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -2061,6 +2072,7 @@ Object { "title": "Small Wooden Computer", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -2169,6 +2181,7 @@ Object { "title": "Practical Granite Pizza", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -2291,6 +2304,7 @@ Object { "title": "Small Wooden Computer", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -2407,6 +2421,7 @@ Object { "title": "Small Wooden Computer", "upc": null, "updated_at": Any, + "variant_rank": 0, "weight": null, "width": null, }, @@ -2414,7 +2429,6 @@ Object { }, ], "allow_backorder": true, - "beforeInsert": [Function], "canceled_at": null, "cart_id": Any, "confirmed_at": Any, diff --git a/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/index.js b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/index.js index 841f9cbef6..37b5589a78 100644 --- a/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/index.js +++ b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/index.js @@ -6,7 +6,7 @@ const { setPort, useApi } = require("../../../helpers/use-api") const adminSeeder = require("../../helpers/admin-seeder") -jest.setTimeout(30000) +jest.setTimeout(50000) const { simpleOrderFactory, @@ -343,8 +343,6 @@ describe("medusa-plugin-sendgrid", () => { expect(response.status).toEqual(200) - expect(response.status).toEqual(200) - const swap = response.data.order.swaps[0] const returnOrder = swap.return_order await api.post( @@ -421,7 +419,6 @@ describe("medusa-plugin-sendgrid", () => { price: 500, }) const api = useApi() - const response = await api.post( `/admin/orders/${order.id}/claims`, { @@ -557,11 +554,14 @@ describe("medusa-plugin-sendgrid", () => { phone: "12353245", }, }) + await api.post(`/store/carts/${cartId}/shipping-methods`, { option_id: shippingOut.id, }) + await api.post(`/store/carts/${cartId}/payment-sessions`) await api.post(`/store/carts/${cartId}/complete`) + const { data: fulfillmentData } = await api.post( `/admin/orders/${order.id}/swaps/${swapId}/fulfillments`, {}, @@ -741,7 +741,6 @@ describe("medusa-plugin-sendgrid", () => { const order = await createReturnableOrder(dbConnection) const api = useApi() - const response = await api.post( `/admin/orders/${order.id}/swaps`, { diff --git a/integration-tests/plugins/factories/simple-product-factory.ts b/integration-tests/plugins/factories/simple-product-factory.ts index 24746c0f84..23288ad6bc 100644 --- a/integration-tests/plugins/factories/simple-product-factory.ts +++ b/integration-tests/plugins/factories/simple-product-factory.ts @@ -1,17 +1,8 @@ import { Connection } from "typeorm" import faker from "faker" -import { - ShippingProfileType, - ShippingProfile, - Product, - ProductType, - ProductOption, -} from "@medusajs/medusa" +import { Product, ProductOption, ProductType, ShippingProfile, ShippingProfileType, } from "@medusajs/medusa" -import { - simpleProductVariantFactory, - ProductVariantFactoryData, -} from "./simple-product-variant-factory" +import { ProductVariantFactoryData, simpleProductVariantFactory, } from "./simple-product-variant-factory" export type ProductFactoryData = { id?: string @@ -34,11 +25,11 @@ export const simpleProductFactory = async ( const manager = connection.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: ShippingProfileType.DEFAULT, + where: { type: ShippingProfileType.DEFAULT }, }) const gcProfile = await manager.findOne(ShippingProfile, { - type: ShippingProfileType.GIFT_CARD, + where: { type: ShippingProfileType.GIFT_CARD }, }) let typeId: string diff --git a/integration-tests/plugins/factories/simple-shipping-option-factory.ts b/integration-tests/plugins/factories/simple-shipping-option-factory.ts index 4ceed9dd97..1df50b3176 100644 --- a/integration-tests/plugins/factories/simple-shipping-option-factory.ts +++ b/integration-tests/plugins/factories/simple-shipping-option-factory.ts @@ -1,11 +1,6 @@ import { Connection } from "typeorm" import faker from "faker" -import { - ShippingOptionPriceType, - ShippingProfile, - ShippingOption, - ShippingProfileType, -} from "@medusajs/medusa" +import { ShippingOption, ShippingOptionPriceType, ShippingProfile, ShippingProfileType, } from "@medusajs/medusa" export type ShippingOptionFactoryData = { name?: string @@ -26,11 +21,11 @@ export const simpleShippingOptionFactory = async ( const manager = connection.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: ShippingProfileType.DEFAULT, + where: { type: ShippingProfileType.DEFAULT }, }) const gcProfile = await manager.findOne(ShippingProfile, { - type: ShippingProfileType.GIFT_CARD, + where: { type: ShippingProfileType.GIFT_CARD }, }) const created = manager.create(ShippingOption, { diff --git a/integration-tests/plugins/factories/simple-store-factory.ts b/integration-tests/plugins/factories/simple-store-factory.ts index 67b7a29c80..893c71c1f3 100644 --- a/integration-tests/plugins/factories/simple-store-factory.ts +++ b/integration-tests/plugins/factories/simple-store-factory.ts @@ -1,22 +1,27 @@ import { SalesChannel, Store } from "@medusajs/medusa" import faker from "faker" -import { Connection } from "typeorm" +import { DataSource, Not, IsNull } from "typeorm" export type StoreFactoryData = { swap_link_template?: string } export const simpleStoreFactory = async ( - connection: Connection, + dataSource: DataSource, data: StoreFactoryData = {}, seed?: number -): Promise => { +): Promise => { if (typeof seed !== "undefined") { faker.seed(seed) } - const manager = connection.manager - const store = await manager.findOne(Store) + const manager = dataSource.manager + const stores = await manager.find(Store, { where: { id: Not(IsNull()) } }) + const store = stores[0] + + if (!store) { + return + } store.swap_link_template = data.swap_link_template ?? "something/{cart_id}" diff --git a/integration-tests/plugins/helpers/cart-seeder.js b/integration-tests/plugins/helpers/cart-seeder.js index b24b85f48c..3e8f488140 100644 --- a/integration-tests/plugins/helpers/cart-seeder.js +++ b/integration-tests/plugins/helpers/cart-seeder.js @@ -14,6 +14,7 @@ const { LineItem, Payment, PaymentSession, + ShippingProfileType, } = require("@medusajs/medusa") module.exports = async (connection, data = {}) => { @@ -34,11 +35,15 @@ module.exports = async (connection, data = {}) => { const manager = connection.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfileType.DEFAULT, + }, }) const gcProfile = await manager.findOne(ShippingProfile, { - type: "gift_card", + where: { + type: ShippingProfileType.GIFT_CARD, + }, }) await manager.insert(Address, { diff --git a/integration-tests/plugins/helpers/draft-order-seeder.js b/integration-tests/plugins/helpers/draft-order-seeder.js index 19b63b0d7c..4013a13cd0 100644 --- a/integration-tests/plugins/helpers/draft-order-seeder.js +++ b/integration-tests/plugins/helpers/draft-order-seeder.js @@ -14,13 +14,16 @@ const { Discount, DiscountRule, Payment, + ShippingProfileType, } = require("@medusajs/medusa") module.exports = async (connection, data = {}) => { const manager = connection.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfileType.DEFAULT, + }, }) await manager.insert(Product, { diff --git a/integration-tests/plugins/helpers/order-seeder.js b/integration-tests/plugins/helpers/order-seeder.js index 2029653dc2..b4a5774a97 100644 --- a/integration-tests/plugins/helpers/order-seeder.js +++ b/integration-tests/plugins/helpers/order-seeder.js @@ -13,13 +13,16 @@ const { ShippingOption, ShippingProfile, Swap, + ShippingProfileType, } = require("@medusajs/medusa") module.exports = async (connection, data = {}) => { const manager = connection.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfileType.DEFAULT, + }, }) await manager.insert(Product, { diff --git a/integration-tests/plugins/helpers/product-seeder.js b/integration-tests/plugins/helpers/product-seeder.js index aef5729fe7..14f5246557 100644 --- a/integration-tests/plugins/helpers/product-seeder.js +++ b/integration-tests/plugins/helpers/product-seeder.js @@ -8,13 +8,16 @@ const { ShippingProfile, ProductVariant, Image, + ShippingProfileType, } = require("@medusajs/medusa") module.exports = async (connection, data = {}) => { const manager = connection.manager const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfileType.DEFAULT, + }, }) const coll = manager.create(ProductCollection, { diff --git a/integration-tests/plugins/helpers/shipping-option-seeder.js b/integration-tests/plugins/helpers/shipping-option-seeder.js index 33d669ca23..3f9f149088 100644 --- a/integration-tests/plugins/helpers/shipping-option-seeder.js +++ b/integration-tests/plugins/helpers/shipping-option-seeder.js @@ -3,6 +3,7 @@ const { ShippingProfile, ShippingOption, ShippingOptionRequirement, + ShippingProfileType, } = require("@medusajs/medusa") module.exports = async (connection, data = {}) => { @@ -16,7 +17,9 @@ module.exports = async (connection, data = {}) => { }) const defaultProfile = await manager.findOne(ShippingProfile, { - type: "default", + where: { + type: ShippingProfileType.DEFAULT, + }, }) await manager.insert(ShippingOption, { diff --git a/integration-tests/plugins/package.json b/integration-tests/plugins/package.json index 92e011efa2..500f221631 100644 --- a/integration-tests/plugins/package.json +++ b/integration-tests/plugins/package.json @@ -14,7 +14,7 @@ "medusa-fulfillment-webshipper": "*", "medusa-interfaces": "*", "medusa-plugin-sendgrid": "*", - "typeorm": "^0.2.31" + "typeorm": "^0.3.11" }, "devDependencies": { "@babel/cli": "^7.12.10", diff --git a/integration-tests/repositories/__tests__/product-categories/queries.ts b/integration-tests/repositories/__tests__/product-categories/queries.ts index 216a9bd1a4..203a2d6fcb 100644 --- a/integration-tests/repositories/__tests__/product-categories/queries.ts +++ b/integration-tests/repositories/__tests__/product-categories/queries.ts @@ -48,7 +48,7 @@ describe("Product Categories", () => { is_active: false }) - productCategoryRepository = dbConnection.manager.getCustomRepository(ProductCategoryRepository) + productCategoryRepository = dbConnection.manager.withRepository(ProductCategoryRepository) }) it("can fetch all root categories", async () => { @@ -133,7 +133,7 @@ describe("Product Categories", () => { } ) - productCategoryRepository = dbConnection.manager.getCustomRepository(ProductCategoryRepository) + productCategoryRepository = dbConnection.manager.withRepository(ProductCategoryRepository) }) it("fetches all active categories", async () => { @@ -200,7 +200,7 @@ describe("Product Categories", () => { const [ categories, count ] = await productCategoryRepository.getFreeTextSearchResultsAndCount( { where: { id: a11.id }, - relations: ['parent_category', 'category_children'], + relations: { parent_category: true, category_children: true }, }, ) diff --git a/integration-tests/repositories/package.json b/integration-tests/repositories/package.json index 8842fbcebe..846ba465e8 100644 --- a/integration-tests/repositories/package.json +++ b/integration-tests/repositories/package.json @@ -10,7 +10,7 @@ "dependencies": { "@medusajs/medusa": "*", "medusa-interfaces": "*", - "typeorm": "^0.2.31" + "typeorm": "^0.3.11" }, "devDependencies": { "@babel/cli": "^7.12.10", diff --git a/package.json b/package.json index 0190819807..fb1b0d0716 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "typedoc-plugin-markdown": "^3.13.4", "typedoc-plugin-merge-modules": "^4.0.1", "typedoc-plugin-reference-excluder": "^1.0.0", - "typeorm": "^0.2.31" + "typeorm": "^0.3.11" }, "lint-staged": { "*.{js,jsx,ts,tsx}": "yarn run lint", diff --git a/packages/inventory/package.json b/packages/inventory/package.json index 3ba7b99791..6b51979f92 100644 --- a/packages/inventory/package.json +++ b/packages/inventory/package.json @@ -21,6 +21,7 @@ "cross-env": "^5.2.1", "jest": "^25.5.4", "ts-jest": "^25.5.1", + "typeorm": "^0.3.11", "typescript": "^4.4.4" }, "scripts": { @@ -32,9 +33,6 @@ }, "peerDependencies": { "@medusajs/medusa": "1.7.7", - "medusa-interfaces": "1.3.6" - }, - "dependencies": { - "typeorm": "^0.2.31" + "typeorm": "^0.3.11" } } diff --git a/packages/inventory/src/services/inventory-item.ts b/packages/inventory/src/services/inventory-item.ts index 4544ec0194..ae86af0cd7 100644 --- a/packages/inventory/src/services/inventory-item.ts +++ b/packages/inventory/src/services/inventory-item.ts @@ -1,11 +1,11 @@ -import { DeepPartial, EntityManager } from "typeorm" +import { DeepPartial, EntityManager, FindManyOptions } from "typeorm" import { isDefined, MedusaError } from "medusa-core-utils" import { - FindConfig, buildQuery, - IEventBusService, - FilterableInventoryItemProps, CreateInventoryItemInput, + FilterableInventoryItemProps, + FindConfig, + IEventBusService, InventoryItemDTO, TransactionBaseService, } from "@medusajs/medusa" @@ -87,7 +87,7 @@ export default class InventoryItemService extends TransactionBaseService { const manager = this.getManager() const itemRepository = manager.getRepository(InventoryItem) - const query = buildQuery({ id: inventoryItemId }, config) + const query = buildQuery({ id: inventoryItemId }, config) as FindManyOptions const [inventoryItem] = await itemRepository.find(query) if (!inventoryItem) { diff --git a/packages/inventory/src/services/inventory-level.ts b/packages/inventory/src/services/inventory-level.ts index 210050c90d..f67fac13ff 100644 --- a/packages/inventory/src/services/inventory-level.ts +++ b/packages/inventory/src/services/inventory-level.ts @@ -1,10 +1,10 @@ -import { DeepPartial, EntityManager } from "typeorm" +import { DeepPartial, EntityManager, FindManyOptions } from "typeorm" import { isDefined, MedusaError } from "medusa-core-utils" import { - FindConfig, buildQuery, - FilterableInventoryLevelProps, CreateInventoryLevelInput, + FilterableInventoryLevelProps, + FindConfig, IEventBusService, TransactionBaseService, } from "@medusajs/medusa" @@ -52,7 +52,7 @@ export default class InventoryLevelService extends TransactionBaseService { const manager = this.getManager() const levelRepository = manager.getRepository(InventoryLevel) - const query = buildQuery(selector, config) + const query = buildQuery(selector, config) as FindManyOptions return await levelRepository.find(query) } @@ -69,7 +69,7 @@ export default class InventoryLevelService extends TransactionBaseService { const manager = this.getManager() const levelRepository = manager.getRepository(InventoryLevel) - const query = buildQuery(selector, config) + const query = buildQuery(selector, config) as FindManyOptions return await levelRepository.findAndCount(query) } @@ -94,7 +94,7 @@ export default class InventoryLevelService extends TransactionBaseService { const manager = this.getManager() const levelRepository = manager.getRepository(InventoryLevel) - const query = buildQuery({ id: inventoryLevelId }, config) + const query = buildQuery({ id: inventoryLevelId }, config) as FindManyOptions const [inventoryLevel] = await levelRepository.find(query) if (!inventoryLevel) { diff --git a/packages/inventory/src/services/reservation-item.ts b/packages/inventory/src/services/reservation-item.ts index 314821b8e8..80b2f6471a 100644 --- a/packages/inventory/src/services/reservation-item.ts +++ b/packages/inventory/src/services/reservation-item.ts @@ -1,4 +1,4 @@ -import { EntityManager } from "typeorm" +import { EntityManager, FindManyOptions } from "typeorm" import { isDefined, MedusaError } from "medusa-core-utils" import { FindConfig, @@ -62,7 +62,7 @@ export default class ReservationItemService extends TransactionBaseService { const manager = this.getManager() const itemRepository = manager.getRepository(ReservationItem) - const query = buildQuery(selector, config) + const query = buildQuery(selector, config) as FindManyOptions return await itemRepository.find(query) } @@ -79,7 +79,7 @@ export default class ReservationItemService extends TransactionBaseService { const manager = this.getManager() const itemRepository = manager.getRepository(ReservationItem) - const query = buildQuery(selector, config) + const query = buildQuery(selector, config) as FindManyOptions return await itemRepository.findAndCount(query) } @@ -104,7 +104,7 @@ export default class ReservationItemService extends TransactionBaseService { const manager = this.getManager() const reservationItemRepository = manager.getRepository(ReservationItem) - const query = buildQuery({ id: reservationItemId }, config) + const query = buildQuery({ id: reservationItemId }, config) as FindManyOptions const [reservationItem] = await reservationItemRepository.find(query) if (!reservationItem) { diff --git a/packages/inventory/src/utils/query.ts b/packages/inventory/src/utils/query.ts index 9fd0f644a9..360b412ae3 100644 --- a/packages/inventory/src/utils/query.ts +++ b/packages/inventory/src/utils/query.ts @@ -1,6 +1,8 @@ -import { EntityManager, ILike } from "typeorm" +import { EntityManager, FindOptionsWhere, ILike } from "typeorm" import { + buildLegacyFieldsListFrom, buildQuery, + ExtendedFindConfig, FilterableInventoryItemProps, FindConfig, } from "@medusajs/medusa" @@ -12,14 +14,19 @@ export function getListQuery( config: FindConfig = { relations: [], skip: 0, take: 10 } ) { const inventoryItemRepository = manager.getRepository(InventoryItem) - const query = buildQuery(selector, config) + + const { q, ...selectorRest } = selector + const query = buildQuery(selectorRest, config) as ExtendedFindConfig & { + where: FindOptionsWhere + } + const queryBuilder = inventoryItemRepository.createQueryBuilder("inv_item") - if (query.where.q) { - query.where.sku = ILike(`%${query.where.q as string}%`) - - delete query.where.q + if (q) { + query.where.sku = ILike(`%${q}%`) } if ("location_id" in query.where) { @@ -50,7 +57,8 @@ export function getListQuery( } if (query.select) { - queryBuilder.select(query.select.map((s) => "inv_item." + s)) + const legacySelect = buildLegacyFieldsListFrom(query.select) + queryBuilder.select(legacySelect.map((s) => "inv_item." + s)) } if (query.order) { diff --git a/packages/medusa-core-utils/src/transform-idable-fields.ts b/packages/medusa-core-utils/src/transform-idable-fields.ts index 6253ba6501..900fa0edf3 100644 --- a/packages/medusa-core-utils/src/transform-idable-fields.ts +++ b/packages/medusa-core-utils/src/transform-idable-fields.ts @@ -25,7 +25,7 @@ type ComputePropertyNames< * ``` */ export const transformIdableFields = < - T = Record, + T extends object = Record, TFields extends (keyof T | string)[] = (keyof T | string)[], TOutput = { [P in ComputePropertyNames]: P extends keyof T diff --git a/packages/medusa-file-minio/package.json b/packages/medusa-file-minio/package.json index a2a6d089f4..4c77ebcead 100644 --- a/packages/medusa-file-minio/package.json +++ b/packages/medusa-file-minio/package.json @@ -26,10 +26,10 @@ "medusa-interfaces": "^1.3.6" }, "scripts": { - "prepare": "cross-env NODE_ENV=production yarn run build", - "test": "jest --passWithNoTests src", "build": "babel src --out-dir dist/ --ignore '**/__tests__','**/__mocks__'", - "watch": "babel -w src --out-dir dist/ --ignore '**/__tests__','**/__mocks__'" + "prepare": "cross-env NODE_ENV=production yarn run build", + "watch": "babel -w src --out-dir dist/ --ignore '**/__tests__','**/__mocks__'", + "test": "jest --passWithNoTests src" }, "peerDependencies": { "medusa-interfaces": "1.3.6" diff --git a/packages/medusa-interfaces/package.json b/packages/medusa-interfaces/package.json index cc0c76ece1..7685f4e4f8 100644 --- a/packages/medusa-interfaces/package.json +++ b/packages/medusa-interfaces/package.json @@ -33,7 +33,6 @@ "jest": "^25.5.4", "medusa-core-utils": "^1.1.39", "medusa-test-utils": "^1.1.37", - "typeorm": "^0.2.29", "typescript": "^4.4.4" }, "peerDependencies": { diff --git a/packages/medusa-interfaces/src/__tests__/base-service.js b/packages/medusa-interfaces/src/__tests__/base-service.js index 978898e61a..76b5055c1f 100644 --- a/packages/medusa-interfaces/src/__tests__/base-service.js +++ b/packages/medusa-interfaces/src/__tests__/base-service.js @@ -1,33 +1,6 @@ import BaseService from "../base-service" -import { In, Not } from "typeorm" describe("BaseService", () => { - describe("buildQuery_", () => { - const baseService = new BaseService() - - it("successfully creates query", () => { - const q = baseService.buildQuery_( - { - id: "1234", - test1: ["123", "12", "1"], - test2: Not("this"), - }, - { - relations: ["1234"], - } - ) - - expect(q).toEqual({ - where: { - id: "1234", - test1: In(["123", "12", "1"]), - test2: Not("this"), - }, - relations: ["1234"], - }) - }) - }) - describe("addDecorator", () => { const baseService = new BaseService() diff --git a/packages/medusa-interfaces/src/base-service.js b/packages/medusa-interfaces/src/base-service.js index 25ac7f71a9..77314e9239 100644 --- a/packages/medusa-interfaces/src/base-service.js +++ b/packages/medusa-interfaces/src/base-service.js @@ -1,11 +1,12 @@ -import { MedusaError } from "medusa-core-utils" -import { FindOperator, In, Raw } from "typeorm" +// Import from dist to avoid circular deps which result in the base service to be undefined +import { buildQuery, setMetadata, validateId } from "@medusajs/medusa/dist/utils" /** * Common functionality for Services * @interface + * @deprecated use TransactionBaseService from @medusajs/medusa instead */ -class BaseService { +export default class BaseService { constructor() { this.decorators_ = [] } @@ -19,93 +20,7 @@ class BaseService { * Used to build TypeORM queries. */ buildQuery_(selector, config = {}) { - const build = (obj) => { - const where = Object.entries(obj).reduce((acc, [key, value]) => { - // Undefined values indicate that they have no significance to the query. - // If the query is looking for rows where a column is not set it should use null instead of undefined - if (typeof value === "undefined") { - return acc - } - switch (true) { - case value instanceof FindOperator: - acc[key] = value - break - case Array.isArray(value): - acc[key] = In([...value]) - break - case value !== null && typeof value === "object": - const subquery = [] - - Object.entries(value).map(([modifier, val]) => { - switch (modifier) { - case "lt": - subquery.push({ operator: "<", value: val }) - break - case "gt": - subquery.push({ operator: ">", value: val }) - break - case "lte": - subquery.push({ operator: "<=", value: val }) - break - case "gte": - subquery.push({ operator: ">=", value: val }) - break - default: - acc[key] = value - break - } - }) - - if (subquery.length) { - acc[key] = Raw( - (a) => - subquery - .map((s, index) => `${a} ${s.operator} :${index}`) - .join(" AND "), - subquery.map((s) => s.value) - ) - } - break - default: - acc[key] = value - break - } - - return acc - }, {}) - - return where - } - - const query = { - where: build(selector), - } - - if ("deleted_at" in selector) { - query.withDeleted = true - } - - if ("skip" in config) { - query.skip = config.skip - } - - if ("take" in config) { - query.take = config.take - } - - if ("relations" in config) { - query.relations = config.relations - } - - if ("select" in config) { - query.select = config.select - } - - if ("order" in config) { - query.order = config.order - } - - return query + return buildQuery(selector, config) } /** @@ -117,32 +32,7 @@ class BaseService { * @returns {string} the rawId given that nothing failed */ validateId_(rawId, config = {}) { - const { prefix, length } = config - if (!rawId) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Failed to validate id: ${rawId}` - ) - } - - if (prefix || length) { - const [pre, rand] = rawId.split("_") - if (prefix && pre !== prefix) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `The provided id: ${rawId} does not adhere to prefix constraint: ${prefix}` - ) - } - - if (length && length !== rand.length) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `The provided id: ${rawId} does not adhere to length constraint: ${length}` - ) - } - } - - return rawId + return validateId(rawId, config) } shouldRetryTransaction(err) { @@ -249,24 +139,7 @@ class BaseService { * @return {Promise} resolves to the updated result. */ setMetadata_(obj, metadata) { - const existing = obj.metadata || {} - const newData = {} - for (const [key, value] of Object.entries(metadata)) { - if (typeof key !== "string") { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "Key type is invalid. Metadata keys must be strings" - ) - } - newData[key] = value - } - - const updated = { - ...existing, - ...newData, - } - - return updated + return setMetadata(obj, metadata) } /** @@ -295,4 +168,3 @@ class BaseService { }, Promise.resolve(obj)) } } -export default BaseService diff --git a/packages/medusa-plugin-sendgrid/src/services/sendgrid.js b/packages/medusa-plugin-sendgrid/src/services/sendgrid.js index 7259b3eecc..d57695a91d 100644 --- a/packages/medusa-plugin-sendgrid/src/services/sendgrid.js +++ b/packages/medusa-plugin-sendgrid/src/services/sendgrid.js @@ -1,6 +1,7 @@ import SendGrid from "@sendgrid/mail" import { humanizeAmount, zeroDecimalCurrencies } from "medusa-core-utils" import { NotificationService } from "medusa-interfaces" +import { IsNull, Not } from "typeorm" class SendGridService extends NotificationService { static identifier = "sendgrid" @@ -621,7 +622,7 @@ class SendGridService extends NotificationService { { id: returnRequest.items.map(({ item_id }) => item_id), }, - { relations: ["tax_lines"] } + { relations: ["tax_lines", "variant", "variant.product"] } ) // Fetch the order @@ -629,6 +630,7 @@ class SendGridService extends NotificationService { select: ["total"], relations: [ "items", + "items.variant", "items.tax_lines", "discounts", "discounts.rule", @@ -712,20 +714,22 @@ class SendGridService extends NotificationService { async swapReceivedData({ id }) { const store = await this.storeService_.retrieve() + const swap = await this.swapService_.retrieve(id, { relations: [ "additional_items", "additional_items.tax_lines", + "additional_items.variant", "return_order", "return_order.items", "return_order.items.item", + "return_order.items.item.variant", "return_order.shipping_method", "return_order.shipping_method.shipping_option", ], }) const returnRequest = swap.return_order - const items = await this.lineItemService_.list( { id: returnRequest.items.map(({ item_id }) => item_id), @@ -752,16 +756,19 @@ class SendGridService extends NotificationService { select: ["total"], relations: [ "items", + "items.variant", "discounts", "discounts.rule", "shipping_address", "swaps", "swaps.additional_items", "swaps.additional_items.tax_lines", + "swaps.additional_items.variant", ], }) const cart = await this.cartService_.retrieve(swap.cart_id, { + relations: ["items", "items.variant", "items.variant.product"], select: [ "total", "tax_total", @@ -770,8 +777,8 @@ class SendGridService extends NotificationService { "subtotal", ], }) - const currencyCode = order.currency_code.toUpperCase() + const currencyCode = order.currency_code.toUpperCase() const decoratedItems = await Promise.all( cart.items.map(async (i) => { const totals = await this.totalsService_.getLineItemTotals(i, cart, { @@ -837,10 +844,11 @@ class SendGridService extends NotificationService { } async swapCreatedData({ id }) { - const store = await this.storeService_.retrieve() + const store = await this.storeService_.retrieve({ where: { id: Not(IsNull()) } }) const swap = await this.swapService_.retrieve(id, { relations: [ "additional_items", + "additional_items.variant.product", "additional_items.tax_lines", "return_order", "return_order.items", @@ -857,7 +865,7 @@ class SendGridService extends NotificationService { id: returnRequest.items.map(({ item_id }) => item_id), }, { - relations: ["tax_lines"], + relations: ["tax_lines", "variant", "variant.product"], } ) @@ -878,6 +886,8 @@ class SendGridService extends NotificationService { select: ["total"], relations: [ "items", + "items.variant", + "items.variant.product", "items.tax_lines", "discounts", "discounts.rule", @@ -885,6 +895,7 @@ class SendGridService extends NotificationService { "swaps", "swaps.additional_items", "swaps.additional_items.tax_lines", + "swaps.additional_items.variant", ], }) @@ -896,6 +907,7 @@ class SendGridService extends NotificationService { "shipping_total", "subtotal", ], + relations: ["items", "items.variant", "items.variant.product"] }) const currencyCode = order.currency_code.toUpperCase() @@ -977,6 +989,8 @@ class SendGridService extends NotificationService { "shipping_methods", "shipping_methods.tax_lines", "additional_items", + "additional_items.variant", + "additional_items.variant.product", "additional_items.tax_lines", "return_order", "return_order.items", @@ -988,10 +1002,14 @@ class SendGridService extends NotificationService { "region", "items", "items.tax_lines", + "items.variant", + "items.variant.product", "discounts", "discounts.rule", "swaps", "swaps.additional_items", + "swaps.additional_items.variant", + "swaps.additional_items.variant.product", "swaps.additional_items.tax_lines", ], }) @@ -1004,6 +1022,11 @@ class SendGridService extends NotificationService { "shipping_total", "subtotal", ], + relations: [ + "items", + "items.variant", + "items.variant.product", + ] }) const returnRequest = swap.return_order @@ -1012,7 +1035,7 @@ class SendGridService extends NotificationService { id: returnRequest.items.map(({ item_id }) => item_id), }, { - relations: ["tax_lines"], + relations: ["tax_lines", "variant", "variant.product"], } ) @@ -1118,7 +1141,13 @@ class SendGridService extends NotificationService { async claimShipmentCreatedData({ id, fulfillment_id }) { const claim = await this.claimService_.retrieve(id, { - relations: ["order", "order.items", "order.shipping_address"], + relations: [ + "order", + "order.items", + "order.items.variant", + "order.items.variant.product", + "order.shipping_address" + ], }) const shipment = await this.fulfillmentService_.retrieve(fulfillment_id, { diff --git a/packages/medusa-test-utils/src/mock-manager.js b/packages/medusa-test-utils/src/mock-manager.js index 59599f4043..2e4fe183d7 100644 --- a/packages/medusa-test-utils/src/mock-manager.js +++ b/packages/medusa-test-utils/src/mock-manager.js @@ -1,17 +1,17 @@ export default { getRepository: function (repo) { - return repo; + return repo }, - getCustomRepository: function (repo) { - return repo; + withRepository: function (repo) { + return repo }, transaction: function (isolationOrCb, cb) { if (typeof isolationOrCb === "string") { - return cb(this); + return cb(this) } else { - return isolationOrCb(this); + return isolationOrCb(this) } }, -}; +} diff --git a/packages/medusa-test-utils/src/mock-repository.js b/packages/medusa-test-utils/src/mock-repository.js index f0c88056ac..eb392f1498 100644 --- a/packages/medusa-test-utils/src/mock-repository.js +++ b/packages/medusa-test-utils/src/mock-repository.js @@ -12,6 +12,7 @@ class MockRepo { save, findAndCount, del, + count, }) { this.create_ = create; this.update_ = update; @@ -28,45 +29,45 @@ class MockRepo { } setFindOne(fn) { - this.findOne_ = fn; + this.findOne_ = fn } create = jest.fn().mockImplementation((...args) => { if (this.create_) { - return this.create_(...args); + return this.create_(...args) } - return {}; - }); + return {} + }) softRemove = jest.fn().mockImplementation((...args) => { if (this.softRemove_) { - return this.softRemove_(...args); + return this.softRemove_(...args) } - return {}; - }); + return {} + }) remove = jest.fn().mockImplementation((...args) => { if (this.remove_) { - return this.remove_(...args); + return this.remove_(...args) } - return {}; - }); + return {} + }) update = jest.fn().mockImplementation((...args) => { if (this.update_) { - return this.update_(...args); + return this.update_(...args) } - }); + }) findOneOrFail = jest.fn().mockImplementation((...args) => { if (this.findOneOrFail_) { - return this.findOneOrFail_(...args); + return this.findOneOrFail_(...args) } - }); + }) findOneWithRelations = jest.fn().mockImplementation((...args) => { if (this.findOneWithRelations_) { - return this.findOneWithRelations_(...args); + return this.findOneWithRelations_(...args) } - }); + }) findOne = jest.fn().mockImplementation((...args) => { if (this.findOne_) { - return this.findOne_(...args); + return this.findOne_(...args) } }); findDescendantsTree = jest.fn().mockImplementation((...args) => { @@ -76,40 +77,46 @@ class MockRepo { }); findOneOrFail = jest.fn().mockImplementation((...args) => { if (this.findOneOrFail_) { - return this.findOneOrFail_(...args); + return this.findOneOrFail_(...args) } - }); + }) find = jest.fn().mockImplementation((...args) => { if (this.find_) { - return this.find_(...args); + return this.find_(...args) } - }); + }) softRemove = jest.fn().mockImplementation((...args) => { if (this.softRemove_) { - return this.softRemove_(...args); + return this.softRemove_(...args) } - }); + }) save = jest.fn().mockImplementation((...args) => { if (this.save_) { - return this.save_(...args); + return this.save_(...args) } - return Promise.resolve(...args); - }); + return Promise.resolve(...args) + }) findAndCount = jest.fn().mockImplementation((...args) => { if (this.findAndCount_) { - return this.findAndCount_(...args); + return this.findAndCount_(...args) } - return {}; - }); + return {} + }) + count = jest.fn().mockImplementation((...args) => { + if (this.count_) { + return this.count(...args) + } + return {} + }) delete = jest.fn().mockImplementation((...args) => { if (this.delete_) { - return this.delete_(...args); + return this.delete_(...args) } - return {}; - }); + return {} + }) } export default (methods = {}) => { - return new MockRepo(methods); -}; + return new MockRepo(methods) +} diff --git a/packages/medusa/package.json b/packages/medusa/package.json index de3de474d9..27d31217fe 100644 --- a/packages/medusa/package.json +++ b/packages/medusa/package.json @@ -45,7 +45,7 @@ }, "peerDependencies": { "medusa-interfaces": "1.3.6", - "typeorm": "0.2.x" + "typeorm": "^0.3.11" }, "dependencies": { "@medusajs/medusa-cli": "^1.3.8", diff --git a/packages/medusa/src/api/routes/admin/inventory-items/utils/join-variants.ts b/packages/medusa/src/api/routes/admin/inventory-items/utils/join-variants.ts index 8f4be84ed0..827c9be2e5 100644 --- a/packages/medusa/src/api/routes/admin/inventory-items/utils/join-variants.ts +++ b/packages/medusa/src/api/routes/admin/inventory-items/utils/join-variants.ts @@ -18,9 +18,14 @@ export const getVariantsByInventoryItemId = async ( inventoryItems.map((item) => item.id) ) - const variants = await productVariantService.list({ - id: variantInventory.map((varInventory) => varInventory.variant_id), - }) + const variants = await productVariantService.list( + { + id: variantInventory.map((varInventory) => varInventory.variant_id), + }, + { + relations: ["product"], + } + ) const variantMap = new Map(variants.map((variant) => [variant.id, variant])) return variantInventory.reduce((acc, cur) => { diff --git a/packages/medusa/src/api/routes/admin/orders/create-swap.ts b/packages/medusa/src/api/routes/admin/orders/create-swap.ts index 25ade65707..df6f1a7650 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-swap.ts @@ -142,9 +142,11 @@ export default async (req, res) => { relations: [ "cart", "items", + "items.variant", "items.tax_lines", "swaps", "swaps.additional_items", + "swaps.additional_items.variant", "swaps.additional_items.tax_lines", ], }) diff --git a/packages/medusa/src/api/routes/admin/orders/index.ts b/packages/medusa/src/api/routes/admin/orders/index.ts index 7ba42e6629..d99822b2f8 100644 --- a/packages/medusa/src/api/routes/admin/orders/index.ts +++ b/packages/medusa/src/api/routes/admin/orders/index.ts @@ -319,6 +319,7 @@ export const defaultAdminOrdersRelations = [ "claims.shipping_methods", "claims.shipping_address", "claims.additional_items", + "claims.additional_items.variant", "claims.fulfillments", "claims.fulfillments.tracking_links", "claims.claim_items", @@ -334,6 +335,7 @@ export const defaultAdminOrdersRelations = [ "swaps.shipping_methods.tax_lines", "swaps.shipping_address", "swaps.additional_items", + "swaps.additional_items.variant", "swaps.fulfillments", "swaps.fulfillments.tracking_links", ] diff --git a/packages/medusa/src/api/routes/admin/shipping-options/index.ts b/packages/medusa/src/api/routes/admin/shipping-options/index.ts index a26ce0433b..fe9af380c4 100644 --- a/packages/medusa/src/api/routes/admin/shipping-options/index.ts +++ b/packages/medusa/src/api/routes/admin/shipping-options/index.ts @@ -33,7 +33,7 @@ export default (app, featureFlagRouter: FlagRouter) => { return app } -export const defaultFields = [ +export const defaultFields: (keyof ShippingOption)[] = [ "id", "name", "region_id", diff --git a/packages/medusa/src/api/routes/admin/shipping-options/update-shipping-option.ts b/packages/medusa/src/api/routes/admin/shipping-options/update-shipping-option.ts index 89d30d7ae1..eebbe5f999 100644 --- a/packages/medusa/src/api/routes/admin/shipping-options/update-shipping-option.ts +++ b/packages/medusa/src/api/routes/admin/shipping-options/update-shipping-option.ts @@ -14,6 +14,8 @@ import { EntityManager } from "typeorm" import TaxInclusivePricingFeatureFlag from "../../../../loaders/feature-flags/tax-inclusive-pricing" import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators" import { validator } from "../../../../utils/validator" +import { ShippingOptionService } from "../../../../services" +import { UpdateShippingOptionInput } from "../../../../types/shipping-options" /** * @oas [post] /shipping-options/{id} @@ -92,9 +94,14 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { option_id } = req.params - const validated = await validator(AdminPostShippingOptionsOptionReq, req.body) + const validated = (await validator( + AdminPostShippingOptionsOptionReq, + req.body + )) as UpdateShippingOptionInput - const optionService = req.scope.resolve("shippingOptionService") + const optionService: ShippingOptionService = req.scope.resolve( + "shippingOptionService" + ) const manager: EntityManager = req.scope.resolve("manager") await manager.transaction(async (transactionManager) => { diff --git a/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js b/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js index 3df4b2f80b..f20facbb21 100644 --- a/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js +++ b/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js @@ -13,6 +13,7 @@ const defaultRelations = [ "shipping_methods", "cart", "cart.items", + "cart.items.variant", "cart.items.adjustments", ] diff --git a/packages/medusa/src/api/routes/admin/swaps/index.ts b/packages/medusa/src/api/routes/admin/swaps/index.ts index aaf5e2ab67..f017caa67c 100644 --- a/packages/medusa/src/api/routes/admin/swaps/index.ts +++ b/packages/medusa/src/api/routes/admin/swaps/index.ts @@ -32,6 +32,7 @@ export const defaultAdminSwapRelations = [ "shipping_methods", "cart", "cart.items", + "cart.items.variant", "cart.items.adjustments", ] diff --git a/packages/medusa/src/api/routes/admin/variants/index.ts b/packages/medusa/src/api/routes/admin/variants/index.ts index 69ba329cd9..84efbc287a 100644 --- a/packages/medusa/src/api/routes/admin/variants/index.ts +++ b/packages/medusa/src/api/routes/admin/variants/index.ts @@ -57,6 +57,8 @@ export const defaultAdminVariantFields: (keyof ProductVariant)[] = [ "created_at", "updated_at", "metadata", + "deleted_at", + "manage_inventory", ] /** diff --git a/packages/medusa/src/api/routes/store/carts/index.ts b/packages/medusa/src/api/routes/store/carts/index.ts index f9bb3b6c99..26adbb964f 100644 --- a/packages/medusa/src/api/routes/store/carts/index.ts +++ b/packages/medusa/src/api/routes/store/carts/index.ts @@ -143,6 +143,7 @@ export const defaultStoreCartRelations = [ "gift_cards", "region", "items", + "items.variant", "items.adjustments", "payment", "shipping_address", diff --git a/packages/medusa/src/api/routes/store/carts/update-line-item.ts b/packages/medusa/src/api/routes/store/carts/update-line-item.ts index d1a9d8d808..6bd71a5bfe 100644 --- a/packages/medusa/src/api/routes/store/carts/update-line-item.ts +++ b/packages/medusa/src/api/routes/store/carts/update-line-item.ts @@ -78,7 +78,7 @@ export default async (req, res) => { } else { const cart = await cartService .withTransaction(m) - .retrieve(id, { relations: ["items"] }) + .retrieve(id, { relations: ["items", "items.variant"] }) const existing = cart.items.find((i) => i.id === line_id) if (!existing) { diff --git a/packages/medusa/src/api/routes/store/orders/index.ts b/packages/medusa/src/api/routes/store/orders/index.ts index 7ece67b6fa..0ee392cb44 100644 --- a/packages/medusa/src/api/routes/store/orders/index.ts +++ b/packages/medusa/src/api/routes/store/orders/index.ts @@ -75,7 +75,6 @@ export const defaultStoreOrdersRelations = [ "fulfillments.tracking_links", "items", "items.variant", - "items.variant.product", "shipping_methods", "discounts", "discounts.rule", diff --git a/packages/medusa/src/api/routes/store/swaps/create-swap.ts b/packages/medusa/src/api/routes/store/swaps/create-swap.ts index 0dd9438921..ce87ad34ab 100644 --- a/packages/medusa/src/api/routes/store/swaps/create-swap.ts +++ b/packages/medusa/src/api/routes/store/swaps/create-swap.ts @@ -140,9 +140,11 @@ export default async (req, res) => { select: ["refunded_total", "total"], relations: [ "items", + "items.variant", "items.tax_lines", "swaps", "swaps.additional_items", + "swaps.additional_items.variant", "swaps.additional_items.tax_lines", ], }) diff --git a/packages/medusa/src/api/routes/store/swaps/index.ts b/packages/medusa/src/api/routes/store/swaps/index.ts index 38880c59cc..1d7da01c4c 100644 --- a/packages/medusa/src/api/routes/store/swaps/index.ts +++ b/packages/medusa/src/api/routes/store/swaps/index.ts @@ -21,6 +21,7 @@ export default (app) => { export const defaultStoreSwapRelations = [ "order", "additional_items", + "additional_items.variant", "return_order", "return_order.shipping_method", "fulfillments", diff --git a/packages/medusa/src/api/routes/store/variants/__tests__/get-variant.js b/packages/medusa/src/api/routes/store/variants/__tests__/get-variant.js index 5090457c54..79dfb059e1 100644 --- a/packages/medusa/src/api/routes/store/variants/__tests__/get-variant.js +++ b/packages/medusa/src/api/routes/store/variants/__tests__/get-variant.js @@ -15,7 +15,7 @@ describe("Get variant by id", () => { it("calls get variant from variantSerice", () => { expect(ProductVariantServiceMock.retrieve).toHaveBeenCalledTimes(1) expect(ProductVariantServiceMock.retrieve).toHaveBeenCalledWith("1", { - relations: ["prices", "options"], + relations: ["prices", "options", "product"], }) }) diff --git a/packages/medusa/src/api/routes/store/variants/index.ts b/packages/medusa/src/api/routes/store/variants/index.ts index b80c9790de..8b8797c0d7 100644 --- a/packages/medusa/src/api/routes/store/variants/index.ts +++ b/packages/medusa/src/api/routes/store/variants/index.ts @@ -27,7 +27,7 @@ export default (app) => { return app } -export const defaultStoreVariantRelations = ["prices", "options"] +export const defaultStoreVariantRelations = ["prices", "options", "product"] /** * @schema StoreVariantsRes diff --git a/packages/medusa/src/commands/migrate.js b/packages/medusa/src/commands/migrate.js index 48d7d6e015..d0a49f7a04 100644 --- a/packages/medusa/src/commands/migrate.js +++ b/packages/medusa/src/commands/migrate.js @@ -1,71 +1,55 @@ -import { createConnection } from "typeorm" +import { asValue, createContainer } from "awilix" import featureFlagLoader from "../loaders/feature-flags" -import configModuleLoader from "../loaders/config" import Logger from "../loaders/logger" - +import databaseLoader from "../loaders/database" +import configModuleLoader from "../loaders/config" import getMigrations, { getModuleSharedResources } from "./utils/get-migrations" const getDataSource = async (directory) => { const configModule = configModuleLoader(directory) - const featureFlagRouter = featureFlagLoader(configModule) - const { coreMigrations } = getMigrations(directory, featureFlagRouter) - const { migrations: moduleMigrations } = getModuleSharedResources( configModule, featureFlagRouter ) - return await createConnection({ - type: configModule.projectConfig.database_type, - url: configModule.projectConfig.database_url, - extra: configModule.projectConfig.database_extra || {}, - schema: configModule.projectConfig.database_schema, - migrations: coreMigrations.concat(moduleMigrations), - logging: true, + const container = createContainer() + container.register("db_entities", asValue([])) + + return await databaseLoader({ + container, + configModule, + customOptions: { + migrations: coreMigrations.concat(moduleMigrations), + logging: "all", + }, }) } const main = async function ({ directory }) { const args = process.argv + args.shift() args.shift() args.shift() + const dataSource = await getDataSource(directory) + if (args[0] === "run") { - const dataSource = await getDataSource(directory) - await dataSource.runMigrations() - await dataSource.close() + await dataSource.destroy() Logger.info("Migrations completed.") process.exit() } else if (args[0] === "revert") { - const dataSource = await getDataSource(directory) - await dataSource.undoLastMigration({ transaction: "all" }) - await dataSource.close() + await dataSource.destroy() Logger.info("Migrations reverted.") - process.exit() } else if (args[0] === "show") { - const configModule = configModuleLoader(directory) - - const featureFlagRouter = featureFlagLoader(configModule) - - const { coreMigrations } = getMigrations(directory, featureFlagRouter) - - const connection = await createConnection({ - type: configModule.projectConfig.database_type, - url: configModule.projectConfig.database_url, - extra: configModule.projectConfig.database_extra || {}, - schema: configModule.projectConfig.database_schema, - migrations: coreMigrations, - logging: true, - }) - - const unapplied = await connection.showMigrations() - await connection.close() + const unapplied = await dataSource.showMigrations() + Logger.info(unapplied) + await dataSource.destroy() process.exit(unapplied ? 1 : 0) } } diff --git a/packages/medusa/src/loaders/__tests__/default.spec.ts b/packages/medusa/src/loaders/__tests__/default.spec.ts index dac47f5edb..c8d6ec517a 100644 --- a/packages/medusa/src/loaders/__tests__/default.spec.ts +++ b/packages/medusa/src/loaders/__tests__/default.spec.ts @@ -1,29 +1,36 @@ -import { asValue, createContainer } from "awilix"; -import { MockRepository, MockManager } from "medusa-test-utils" -import { StoreServiceMock } from "../../services/__mocks__/store"; -import { ShippingProfileServiceMock } from "../../services/__mocks__/shipping-profile"; -import Logger from "../logger"; -import featureFlagsLoader from "../feature-flags"; +import { asValue, createContainer } from "awilix" +import { MockManager, MockRepository } from "medusa-test-utils" +import { StoreServiceMock } from "../../services/__mocks__/store" +import { ShippingProfileServiceMock } from "../../services/__mocks__/shipping-profile" +import Logger from "../logger" +import featureFlagsLoader from "../feature-flags" import { default as defaultLoader } from "../defaults" -import { SalesChannelServiceMock } from "../../services/__mocks__/sales-channel"; -import { PaymentProviderServiceMock } from "../../services/__mocks__/payment-provider"; +import { SalesChannelServiceMock } from "../../services/__mocks__/sales-channel" +import { PaymentProviderServiceMock } from "../../services/__mocks__/payment-provider" -describe('default', () => { - describe('sales channel default', () => { +describe("default", () => { + describe("sales channel default", () => { let featureFlagRouter const container = createContainer() beforeAll(async () => { - featureFlagRouter = await featureFlagsLoader({ - featureFlags: { - sales_channels: true, + featureFlagRouter = await featureFlagsLoader( + { + featureFlags: { + sales_channels: true, + }, }, - }, Logger) + Logger + ) container.register({ storeService: asValue(StoreServiceMock), currencyRepository: asValue(MockRepository()), - countryRepository: asValue(MockRepository()), + countryRepository: asValue( + MockRepository({ + count: jest.fn().mockImplementation(() => 1), + }) + ), shippingProfileService: asValue(ShippingProfileServiceMock), salesChannelService: asValue(SalesChannelServiceMock), logger: asValue(Logger), diff --git a/packages/medusa/src/loaders/database.ts b/packages/medusa/src/loaders/database.ts index 54216e966d..e5003f4314 100644 --- a/packages/medusa/src/loaders/database.ts +++ b/packages/medusa/src/loaders/database.ts @@ -1,48 +1,66 @@ import { - Connection, - createConnection, - getConnectionManager, - getConnection, + DataSource, + DataSourceOptions, + Repository, + TreeRepository, } from "typeorm" -import { ShortenedNamingStrategy } from "../utils/naming-strategy" import { AwilixContainer } from "awilix" -import { ConnectionOptions } from "typeorm/connection/ConnectionOptions" import { ConfigModule } from "../types/global" +import "../utils/naming-strategy" type Options = { configModule: ConfigModule container: AwilixContainer + customOptions?: { + migrations: DataSourceOptions["migrations"] + logging: DataSourceOptions["logging"] + } +} + +export let dataSource: DataSource + +// TODO: With the latest version of typeorm, the datasource is expected to be +// available globally. During the integration test, the medusa +// files are imported from @medusajs/medusa, therefore, the repositories are +// evaluated at the same time, unfortunately, the integration tests have their +// own way to load and at the moment, the datasource does not exists. This is +// why we are mocking them here +if (process.env.NODE_ENV === "test") { + dataSource = { + getRepository: (target) => new Repository(target, {} as any) as any, + getTreeRepository: (target) => new TreeRepository(target, {} as any) as any, + } as unknown as DataSource } export default async ({ container, configModule, -}: Options): Promise => { + customOptions, +}: Options): Promise => { const entities = container.resolve("db_entities") const isSqlite = configModule.projectConfig.database_type === "sqlite" - const cnnManager = getConnectionManager() - if (cnnManager.has("default") && getConnection().isConnected) { - await getConnection().close() - } - - const connection = await createConnection({ + dataSource = new DataSource({ type: configModule.projectConfig.database_type, url: configModule.projectConfig.database_url, database: configModule.projectConfig.database_database, extra: configModule.projectConfig.database_extra || {}, schema: configModule.projectConfig.database_schema, entities, - namingStrategy: new ShortenedNamingStrategy(), - logging: configModule.projectConfig.database_logging || false, - } as ConnectionOptions) + migrations: customOptions?.migrations, + logging: + customOptions?.logging ?? + (configModule.projectConfig.database_logging || false), + } as DataSourceOptions) + + await dataSource.initialize() if (isSqlite) { - await connection.query(`PRAGMA foreign_keys = OFF`) - await connection.synchronize() - await connection.query(`PRAGMA foreign_keys = ON`) + await dataSource.query(`PRAGMA foreign_keys = OFF`) + await dataSource.synchronize() + await dataSource.query(`PRAGMA foreign_keys = ON`) } - return connection + return dataSource } diff --git a/packages/medusa/src/loaders/defaults.ts b/packages/medusa/src/loaders/defaults.ts index 29268e061a..133e0c6d1c 100644 --- a/packages/medusa/src/loaders/defaults.ts +++ b/packages/medusa/src/loaders/defaults.ts @@ -78,8 +78,8 @@ export default async ({ const entityManager = container.resolve("manager") await entityManager.transaction(async (manager: EntityManager) => { - const countryRepo = manager.getCustomRepository(countryRepository) - const hasCountries = await countryRepo.findOne() + const countryRepo = manager.withRepository(countryRepository) + const hasCountries = !!(await countryRepo.count()) if (!hasCountries) { for (const c of countries) { const query = `INSERT INTO "country" ("iso_2", "iso_3", "num_code", "name", "display_name") @@ -103,8 +103,8 @@ export default async ({ }) await entityManager.transaction(async (manager: EntityManager) => { - const currencyRepo = manager.getCustomRepository(currencyRepository) - const hasCurrencies = await currencyRepo.findOne() + const currencyRepo = manager.withRepository(currencyRepository) + const hasCurrencies = !!(await currencyRepo.count()) if (!hasCurrencies) { for (const [, c] of Object.entries(currencies)) { const query = `INSERT INTO "currency" ("code", "symbol", "symbol_native", "name") diff --git a/packages/medusa/src/loaders/index.ts b/packages/medusa/src/loaders/index.ts index 5397000efc..469b2d1d45 100644 --- a/packages/medusa/src/loaders/index.ts +++ b/packages/medusa/src/loaders/index.ts @@ -11,11 +11,11 @@ import { track } from "medusa-telemetry" import { EOL } from "os" import "reflect-metadata" import requestIp from "request-ip" -import { Connection, getManager } from "typeorm" +import { Connection } from "typeorm" import { MedusaContainer } from "../types/global" import apiLoader from "./api" import loadConfig from "./config" -import databaseLoader from "./database" +import databaseLoader, { dataSource } from "./database" import defaultsLoader from "./defaults" import expressLoader from "./express" import featureFlagsLoader from "./feature-flags" @@ -109,12 +109,6 @@ export default async ({ const pmAct = Logger.success(pmActivity, "Plugin models initialized") || {} track("PLUGIN_MODELS_INIT_COMPLETED", { duration: pmAct.duration }) - const repoActivity = Logger.activity(`Initializing repositories${EOL}`) - track("REPOSITORIES_INIT_STARTED") - repositoriesLoader({ container }) - const rAct = Logger.success(repoActivity, "Repositories initialized") || {} - track("REPOSITORIES_INIT_COMPLETED", { duration: rAct.duration }) - const stratActivity = Logger.activity(`Initializing strategies${EOL}`) track("STRATEGIES_INIT_STARTED") strategiesLoader({ container, configModule, isTest }) @@ -136,7 +130,13 @@ export default async ({ const dbAct = Logger.success(dbActivity, "Database initialized") || {} track("DATABASE_INIT_COMPLETED", { duration: dbAct.duration }) - container.register({ manager: asValue(dbConnection.manager) }) + const repoActivity = Logger.activity(`Initializing repositories${EOL}`) + track("REPOSITORIES_INIT_STARTED") + repositoriesLoader({ container }) + const rAct = Logger.success(repoActivity, "Repositories initialized") || {} + track("REPOSITORIES_INIT_COMPLETED", { duration: rAct.duration }) + + container.register({ manager: asValue(dataSource.manager) }) const servicesActivity = Logger.activity(`Initializing services${EOL}`) track("SERVICES_INIT_STARTED") @@ -153,7 +153,7 @@ export default async ({ // Add the registered services to the request scope expressApp.use((req: Request, res: Response, next: NextFunction) => { - container.register({ manager: asValue(getManager()) }) + container.register({ manager: asValue(dataSource.manager) }) ;(req as any).scope = container.createScope() next() }) diff --git a/packages/medusa/src/loaders/repositories.ts b/packages/medusa/src/loaders/repositories.ts index 9735ba3b87..f640229f90 100644 --- a/packages/medusa/src/loaders/repositories.ts +++ b/packages/medusa/src/loaders/repositories.ts @@ -1,9 +1,9 @@ import glob from "glob" import path from "path" -import { asClass } from "awilix" import formatRegistrationName from "../utils/format-registration-name" -import { ClassConstructor, MedusaContainer } from "../types/global" +import { MedusaContainer } from "../types/global" +import { asValue } from "awilix" /** * Registers all models in the model directory @@ -14,17 +14,13 @@ export default ({ container }: { container: MedusaContainer }): void => { const core = glob.sync(coreFull, { cwd: __dirname }) core.forEach((fn) => { - const loaded = require(fn) as ClassConstructor + const loaded = require(fn).default - Object.entries(loaded).map( - ([, val]: [string, ClassConstructor]) => { - if (typeof val === "function") { - const name = formatRegistrationName(fn) - container.register({ - [name]: asClass(val), - }) - } - } - ) + if (typeof loaded === "object") { + const name = formatRegistrationName(fn) + container.register({ + [name]: asValue(loaded), + }) + } }) } diff --git a/packages/medusa/src/models/discount-condition.ts b/packages/medusa/src/models/discount-condition.ts index 4ff8ac2434..c44616c947 100644 --- a/packages/medusa/src/models/discount-condition.ts +++ b/packages/medusa/src/models/discount-condition.ts @@ -7,6 +7,7 @@ import { JoinTable, ManyToMany, ManyToOne, + OneToMany, Unique, } from "typeorm" @@ -19,6 +20,7 @@ import { ProductTag } from "./product-tag" import { ProductType } from "./product-type" import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" import { generateEntityId } from "../utils/generate-entity-id" +import { Discount } from "./discount" export enum DiscountConditionType { PRODUCTS = "products", diff --git a/packages/medusa/src/models/line-item.ts b/packages/medusa/src/models/line-item.ts index ef51aab919..8e39cf34df 100644 --- a/packages/medusa/src/models/line-item.ts +++ b/packages/medusa/src/models/line-item.ts @@ -118,7 +118,7 @@ export class LineItem extends BaseEntity { @Column({ nullable: true, type: "text" }) variant_id: string | null - @ManyToOne(() => ProductVariant, { eager: true }) + @ManyToOne(() => ProductVariant) @JoinColumn({ name: "variant_id" }) variant: ProductVariant diff --git a/packages/medusa/src/models/order.ts b/packages/medusa/src/models/order.ts index 06453adb1d..24a58b7ad6 100644 --- a/packages/medusa/src/models/order.ts +++ b/packages/medusa/src/models/order.ts @@ -11,15 +11,8 @@ import { OneToMany, OneToOne, } from "typeorm" -import { - DbAwareColumn, - resolveDbGenerationStrategy, - resolveDbType, -} from "../utils/db-aware-column" -import { - FeatureFlagColumn, - FeatureFlagDecorators, -} from "../utils/feature-flag-decorators" +import { DbAwareColumn, resolveDbGenerationStrategy, resolveDbType, } from "../utils/db-aware-column" +import { FeatureFlagColumn, FeatureFlagDecorators, } from "../utils/feature-flag-decorators" import { BaseEntity } from "../interfaces/models/base-entity" import { generateEntityId } from "../utils/generate-entity-id" diff --git a/packages/medusa/src/models/product-variant.ts b/packages/medusa/src/models/product-variant.ts index b8e39695ba..d65def55ce 100644 --- a/packages/medusa/src/models/product-variant.ts +++ b/packages/medusa/src/models/product-variant.ts @@ -1,3 +1,8 @@ +import { DbAwareColumn, generateEntityId } from "../utils" +import { MoneyAmount } from "./money-amount" +import { Product } from "./product" +import { ProductOptionValue } from "./product-option-value" +import { SoftDeletableEntity } from "../interfaces" import { BeforeInsert, Column, @@ -5,15 +10,9 @@ import { Index, JoinColumn, ManyToOne, - OneToMany, + OneToMany } from "typeorm" -import { DbAwareColumn } from "../utils/db-aware-column" -import { MoneyAmount } from "./money-amount" -import { Product } from "./product" -import { ProductOptionValue } from "./product-option-value" -import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" -import { generateEntityId } from "../utils/generate-entity-id" import { ProductVariantInventoryItem } from "./product-variant-inventory-item" @Entity() @@ -25,7 +24,7 @@ export class ProductVariant extends SoftDeletableEntity { @Column() product_id: string - @ManyToOne(() => Product, (product) => product.variants, { eager: true }) + @ManyToOne(() => Product, (product) => product.variants) @JoinColumn({ name: "product_id" }) product: Product @@ -51,7 +50,7 @@ export class ProductVariant extends SoftDeletableEntity { @Index({ unique: true, where: "deleted_at IS NULL" }) upc: string - @Column({ nullable: true, default: 0, select: false }) + @Column({ nullable: true, default: 0 }) variant_rank: number @Column({ type: "int" }) diff --git a/packages/medusa/src/repositories/address.ts b/packages/medusa/src/repositories/address.ts index 2a072519fb..f9020ea03c 100644 --- a/packages/medusa/src/repositories/address.ts +++ b/packages/medusa/src/repositories/address.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Address } from "../models/address" +import { Address } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Address) -export class AddressRepository extends Repository
{} +export const AddressRepository = dataSource.getRepository(Address) +export default AddressRepository diff --git a/packages/medusa/src/repositories/analytics-config.ts b/packages/medusa/src/repositories/analytics-config.ts index 54762f57d4..00e55f1fa3 100644 --- a/packages/medusa/src/repositories/analytics-config.ts +++ b/packages/medusa/src/repositories/analytics-config.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" import { AnalyticsConfig } from "../models/analytics-config" +import { dataSource } from "../loaders/database" -@EntityRepository(AnalyticsConfig) -export class AnalyticsConfigRepository extends Repository {} +export const AnalyticsConfigRepository = dataSource.getRepository(AnalyticsConfig) +export default AnalyticsConfigRepository diff --git a/packages/medusa/src/repositories/batch-job.ts b/packages/medusa/src/repositories/batch-job.ts index eee8cfe738..1db24e986b 100644 --- a/packages/medusa/src/repositories/batch-job.ts +++ b/packages/medusa/src/repositories/batch-job.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" import { BatchJob } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(BatchJob) -export class BatchJobRepository extends Repository {} +export const BatchJobRepository = dataSource.getRepository(BatchJob) +export default BatchJobRepository diff --git a/packages/medusa/src/repositories/cart.ts b/packages/medusa/src/repositories/cart.ts index 66c1b23f3d..8ab763bee4 100644 --- a/packages/medusa/src/repositories/cart.ts +++ b/packages/medusa/src/repositories/cart.ts @@ -1,53 +1,5 @@ -import { flatten, groupBy, map, merge } from "lodash" -import { EntityRepository, FindManyOptions, Repository } from "typeorm" -import { Cart } from "../models/cart" +import { Cart } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Cart) -export class CartRepository extends Repository { - public async findWithRelations( - relations: string[] = [], - optionsWithoutRelations: Omit, "relations"> = {} - ): Promise { - const entities = await this.find(optionsWithoutRelations) - const entitiesIds = entities.map(({ id }) => id) - - const groupedRelations = {} - for (const rel of relations) { - const [topLevel] = rel.split(".") - if (groupedRelations[topLevel]) { - groupedRelations[topLevel].push(rel) - } else { - groupedRelations[topLevel] = [rel] - } - } - - const entitiesIdsWithRelations = await Promise.all( - Object.entries(groupedRelations).map(async ([_, rels]) => { - return this.findByIds(entitiesIds, { - select: ["id"], - relations: rels as string[], - }) - }) - ).then(flatten) - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) - - const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id") - return map(entitiesAndRelationsById, (entityAndRelations) => - merge({}, ...entityAndRelations) - ) - } - - public async findOneWithRelations( - relations: string[] = [], - optionsWithoutRelations: Omit, "relations"> = {} - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const result = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - } -} +export const CartRepository = dataSource.getRepository(Cart) +export default CartRepository diff --git a/packages/medusa/src/repositories/claim-image.ts b/packages/medusa/src/repositories/claim-image.ts index 243b7e7d95..ee6a840043 100644 --- a/packages/medusa/src/repositories/claim-image.ts +++ b/packages/medusa/src/repositories/claim-image.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" import { ClaimImage } from "../models/claim-image" +import { dataSource } from "../loaders/database" -@EntityRepository(ClaimImage) -export class ClaimImageRepository extends Repository {} +export const ClaimImageRepository = dataSource.getRepository(ClaimImage) +export default ClaimImageRepository diff --git a/packages/medusa/src/repositories/claim-item.ts b/packages/medusa/src/repositories/claim-item.ts index 560b39c886..b2231d6cef 100644 --- a/packages/medusa/src/repositories/claim-item.ts +++ b/packages/medusa/src/repositories/claim-item.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" import { ClaimItem } from "../models/claim-item" +import { dataSource } from "../loaders/database" -@EntityRepository(ClaimItem) -export class ClaimItemRepository extends Repository {} +export const ClaimItemRepository = dataSource.getRepository(ClaimItem) +export default ClaimItemRepository diff --git a/packages/medusa/src/repositories/claim-tag.ts b/packages/medusa/src/repositories/claim-tag.ts index 9fe826e4de..ddf29503e7 100644 --- a/packages/medusa/src/repositories/claim-tag.ts +++ b/packages/medusa/src/repositories/claim-tag.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" import { ClaimTag } from "../models/claim-tag" +import { dataSource } from "../loaders/database" -@EntityRepository(ClaimTag) -export class ClaimTagRepository extends Repository {} +export const ClaimTagRepository = dataSource.getRepository(ClaimTag) +export default ClaimTagRepository diff --git a/packages/medusa/src/repositories/claim.ts b/packages/medusa/src/repositories/claim.ts index 863d387ff8..669912d905 100644 --- a/packages/medusa/src/repositories/claim.ts +++ b/packages/medusa/src/repositories/claim.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" import { ClaimOrder } from "../models/claim-order" +import { dataSource } from "../loaders/database" -@EntityRepository(ClaimOrder) -export class ClaimRepository extends Repository {} +export const ClaimRepository = dataSource.getRepository(ClaimOrder) +export default ClaimRepository diff --git a/packages/medusa/src/repositories/country.ts b/packages/medusa/src/repositories/country.ts index 40acbc175a..5072ea84c1 100644 --- a/packages/medusa/src/repositories/country.ts +++ b/packages/medusa/src/repositories/country.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" import { Country } from "../models/country" +import { dataSource } from "../loaders/database" -@EntityRepository(Country) -export class CountryRepository extends Repository {} +export const CountryRepository = dataSource.getRepository(Country) +export default CountryRepository diff --git a/packages/medusa/src/repositories/currency.ts b/packages/medusa/src/repositories/currency.ts index b65e9f0e7d..744ad6d508 100644 --- a/packages/medusa/src/repositories/currency.ts +++ b/packages/medusa/src/repositories/currency.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" import { Currency } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Currency) -export class CurrencyRepository extends Repository {} +export const CurrencyRepository = dataSource.getRepository(Currency) +export default CurrencyRepository diff --git a/packages/medusa/src/repositories/custom-shipping-option.ts b/packages/medusa/src/repositories/custom-shipping-option.ts index 89f1d75017..15fcca2cf1 100644 --- a/packages/medusa/src/repositories/custom-shipping-option.ts +++ b/packages/medusa/src/repositories/custom-shipping-option.ts @@ -1,6 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" -import { CustomShippingOption } from "./../models/custom-shipping-option" +import { CustomShippingOption } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(CustomShippingOption) -// eslint-disable-next-line max-len -export class CustomShippingOptionRepository extends Repository {} +export const CustomShippingOptionRepository = + dataSource.getRepository(CustomShippingOption) +export default CustomShippingOptionRepository diff --git a/packages/medusa/src/repositories/customer-group.ts b/packages/medusa/src/repositories/customer-group.ts index 3605696660..4d0af40277 100644 --- a/packages/medusa/src/repositories/customer-group.ts +++ b/packages/medusa/src/repositories/customer-group.ts @@ -1,22 +1,23 @@ import { DeleteResult, - EntityRepository, FindOperator, + FindOptionsRelations, In, - Repository, SelectQueryBuilder, } from "typeorm" import { CustomerGroup } from "../models" -import { ExtendedFindConfig, Selector } from "../types/common" +import { ExtendedFindConfig } from "../types/common" import { getGroupedRelations, mergeEntitiesWithRelations, queryEntityWithIds, queryEntityWithoutRelations, } from "../utils/repository" +import { buildLegacyFieldsListFrom } from "../utils" +import { dataSource } from "../loaders/database" export type DefaultWithoutRelations = Omit< - ExtendedFindConfig>, + ExtendedFindConfig, "relations" > @@ -26,118 +27,134 @@ export type FindWithoutRelationsOptions = DefaultWithoutRelations & { } } -@EntityRepository(CustomerGroup) -export class CustomerGroupRepository extends Repository { - async addCustomers( - groupId: string, - customerIds: string[] - ): Promise { - const customerGroup = await this.findOne(groupId) - - await this.createQueryBuilder() - .insert() - .into("customer_group_customers") - .values( - customerIds.map((id) => ({ - customer_id: id, - customer_group_id: groupId, - })) - ) - .orIgnore() - .execute() - - return customerGroup as CustomerGroup - } - - async removeCustomers( - groupId: string, - customerIds: string[] - ): Promise { - return await this.createQueryBuilder() - .delete() - .from("customer_group_customers") - .where({ - customer_group_id: groupId, - customer_id: In(customerIds), +export const CustomerGroupRepository = dataSource + .getRepository(CustomerGroup) + .extend({ + async addCustomers( + groupId: string, + customerIds: string[] + ): Promise { + const customerGroup = await this.findOne({ + where: { + id: groupId, + }, }) - .execute() - } - public async findWithRelationsAndCount( - relations: string[] = [], - idsOrOptionsWithoutRelations: FindWithoutRelationsOptions = { where: {} } - ): Promise<[CustomerGroup[], number]> { - let count: number - let entities: CustomerGroup[] - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.findByIds(idsOrOptionsWithoutRelations, { - withDeleted: idsOrOptionsWithoutRelations.withDeleted ?? false, - }) - count = entities.length - } else { - const customJoinsBuilders: (( - qb: SelectQueryBuilder, - alias: string - ) => void)[] = [] - - if (idsOrOptionsWithoutRelations?.where?.discount_condition_id) { - const discountConditionId = - idsOrOptionsWithoutRelations?.where?.discount_condition_id - delete idsOrOptionsWithoutRelations?.where?.discount_condition_id - - customJoinsBuilders.push( - (qb: SelectQueryBuilder, alias: string) => { - qb.innerJoin( - "discount_condition_customer_group", - "dc_cg", - `dc_cg.customer_group_id = ${alias}.id AND dc_cg.condition_id = :dcId`, - { dcId: discountConditionId } - ) - } + await this.createQueryBuilder() + .insert() + .into("customer_group_customers") + .values( + customerIds.map((id) => ({ + customer_id: id, + customer_group_id: groupId, + })) ) + .orIgnore() + .execute() + + return customerGroup as CustomerGroup + }, + + async removeCustomers( + groupId: string, + customerIds: string[] + ): Promise { + return await this.createQueryBuilder() + .delete() + .from("customer_group_customers") + .where({ + customer_group_id: groupId, + customer_id: In(customerIds), + }) + .execute() + }, + + async findWithRelationsAndCount( + relations: FindOptionsRelations = {}, + idsOrOptionsWithoutRelations: FindWithoutRelationsOptions = { where: {} } + ): Promise<[CustomerGroup[], number]> { + let count: number + let entities: CustomerGroup[] + if (Array.isArray(idsOrOptionsWithoutRelations)) { + entities = await this.find({ + where: { id: In(idsOrOptionsWithoutRelations) }, + withDeleted: idsOrOptionsWithoutRelations.withDeleted ?? false, + }) + count = entities.length + } else { + const customJoinsBuilders: (( + qb: SelectQueryBuilder, + alias: string + ) => void)[] = [] + + if (idsOrOptionsWithoutRelations?.where?.discount_condition_id) { + const discountConditionId = + idsOrOptionsWithoutRelations?.where?.discount_condition_id + delete idsOrOptionsWithoutRelations?.where?.discount_condition_id + + customJoinsBuilders.push( + (qb: SelectQueryBuilder, alias: string) => { + qb.innerJoin( + "discount_condition_customer_group", + "dc_cg", + `dc_cg.customer_group_id = ${alias}.id AND dc_cg.condition_id = :dcId`, + { dcId: discountConditionId } + ) + } + ) + } + + const result = await queryEntityWithoutRelations( + this, + idsOrOptionsWithoutRelations, + true, + customJoinsBuilders + ) + entities = result[0] + count = result[1] + } + const entitiesIds = entities.map(({ id }) => id) + + if (entitiesIds.length === 0) { + // no need to continue + return [[], count] } - const result = await queryEntityWithoutRelations( - this, - idsOrOptionsWithoutRelations, - true, - customJoinsBuilders + if (Object.keys(relations).length === 0) { + const options = { ...idsOrOptionsWithoutRelations } + + // Since we are finding by the ids that have been retrieved above and those ids are already + // applying skip/take. Remove those options to avoid getting no results + delete options.skip + delete options.take + + const toReturn = await this.find({ + ...options, + where: { id: In(entitiesIds) }, + }) + return [toReturn, toReturn.length] + } + + const legacyRelations = buildLegacyFieldsListFrom(relations) + const groupedRelations = getGroupedRelations(legacyRelations) + + const legacySelect = buildLegacyFieldsListFrom( + idsOrOptionsWithoutRelations.select + ) + const entitiesIdsWithRelations = await queryEntityWithIds( + this, + entitiesIds, + groupedRelations, + idsOrOptionsWithoutRelations.withDeleted, + legacySelect ) - entities = result[0] - count = result[1] - } - const entitiesIds = entities.map(({ id }) => id) - if (entitiesIds.length === 0) { - // no need to continue - return [[], count] - } + const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) + const entitiesToReturn = + mergeEntitiesWithRelations(entitiesAndRelations) - if (relations.length === 0) { - const options = { ...idsOrOptionsWithoutRelations } + return [entitiesToReturn, count] + }, + }) - // Since we are finding by the ids that have been retrieved above and those ids are already - // applying skip/take. Remove those options to avoid getting no results - delete options.skip - delete options.take - - const toReturn = await this.findByIds(entitiesIds, options) - return [toReturn, toReturn.length] - } - - const groupedRelations = getGroupedRelations(relations) - const entitiesIdsWithRelations = await queryEntityWithIds( - this, - entitiesIds, - groupedRelations, - idsOrOptionsWithoutRelations.withDeleted, - idsOrOptionsWithoutRelations.select - ) - - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) - const entitiesToReturn = - mergeEntitiesWithRelations(entitiesAndRelations) - - return [entitiesToReturn, count] - } -} +export default CustomerGroupRepository diff --git a/packages/medusa/src/repositories/customer.ts b/packages/medusa/src/repositories/customer.ts index 3bf79e0262..fe67ae6472 100644 --- a/packages/medusa/src/repositories/customer.ts +++ b/packages/medusa/src/repositories/customer.ts @@ -1,49 +1,49 @@ -import { Brackets, EntityRepository, ILike, Repository } from "typeorm" -import { Customer } from "../models/customer" -import { ExtendedFindConfig, Selector } from "../types/common" +import { FindOperator, FindOptionsWhere, ILike, In } from "typeorm" +import { Customer } from "../models" +import { dataSource } from "../loaders/database" +import { ExtendedFindConfig } from "../types/common" -@EntityRepository(Customer) -export class CustomerRepository extends Repository { +export const CustomerRepository = dataSource.getRepository(Customer).extend({ async listAndCount( - query: ExtendedFindConfig>, + query: ExtendedFindConfig & { + where: FindOptionsWhere }> + }, q: string | undefined = undefined ): Promise<[Customer[], number]> { - const groups = query.where.groups as { value: string[] } - delete query.where.groups + const query_ = { ...query } - const qb = this.createQueryBuilder("customer") - .skip(query.skip) - .take(query.take) + if (query_.where.groups) { + query_.relations = query_.relations ?? {} + query_.relations.groups = query_.relations.groups ?? true + + query.where.groups = { + id: In((query_.where.groups as FindOperator).value), + } + } if (q) { - delete query.where.email - delete query.where.first_name - delete query.where.last_name + query_.where = query_.where as FindOptionsWhere + delete query_.where.email + delete query_.where.first_name + delete query_.where.last_name - qb.where( - new Brackets((qb) => { - qb.where({ email: ILike(`%${q}%`) }) - .orWhere({ first_name: ILike(`%${q}%`) }) - .orWhere({ last_name: ILike(`%${q}%`) }) - }) - ) + query_.where = [ + { + ...query_.where, + email: ILike(`%${q}%`), + }, + { + ...query_.where, + first_name: ILike(`%${q}%`), + }, + { + ...query_.where, + last_name: ILike(`%${q}%`), + }, + ] } - qb.andWhere(query.where) - - if (groups) { - qb.leftJoinAndSelect("customer.groups", "group").andWhere( - `group.id IN (:...ids)`, - { ids: groups.value } - ) - } - - if (query.relations?.length) { - query.relations.forEach((rel) => { - qb.leftJoinAndSelect(`customer.${rel}`, rel) - }) - } - - return await qb.getManyAndCount() - } -} + return await this.findAndCount(query_) + }, +}) +export default CustomerRepository diff --git a/packages/medusa/src/repositories/discount-condition.ts b/packages/medusa/src/repositories/discount-condition.ts index f464d5b776..6b34d27d83 100644 --- a/packages/medusa/src/repositories/discount-condition.ts +++ b/packages/medusa/src/repositories/discount-condition.ts @@ -1,11 +1,4 @@ -import { - DeleteResult, - EntityRepository, - EntityTarget, - In, - Not, - Repository, -} from "typeorm" +import { DeleteResult, EntityTarget, In, Not } from "typeorm" import { Discount, DiscountCondition, @@ -18,6 +11,7 @@ import { DiscountConditionType, } from "../models" import { isString } from "../utils" +import { dataSource } from "../loaders/database" export enum DiscountConditionJoinTableForeignKey { PRODUCT_ID = "product_id", @@ -35,301 +29,305 @@ type DiscountConditionResourceType = EntityTarget< | DiscountConditionCustomerGroup > -@EntityRepository(DiscountCondition) -export class DiscountConditionRepository extends Repository { - async findOneWithDiscount( - conditionId: string, - discountId: string - ): Promise<(DiscountCondition & { discount: Discount }) | undefined> { - return (await this.createQueryBuilder("condition") - .leftJoinAndMapOne( - "condition.discount", - Discount, - "discount", - `condition.discount_rule_id = discount.rule_id and discount.id = :discId and condition.id = :dcId`, - { discId: discountId, dcId: conditionId } - ) - .getOne()) as (DiscountCondition & { discount: Discount }) | undefined - } +export const DiscountConditionRepository = dataSource + .getRepository(DiscountCondition) + .extend({ + async findOneWithDiscount( + conditionId: string, + discountId: string + ): Promise<(DiscountCondition & { discount: Discount }) | undefined> { + return (await this.createQueryBuilder("condition") + .leftJoinAndMapOne( + "condition.discount", + Discount, + "discount", + `condition.discount_rule_id = discount.rule_id and discount.id = :discId and condition.id = :dcId`, + { discId: discountId, dcId: conditionId } + ) + .getOne()) as (DiscountCondition & { discount: Discount }) | undefined + }, - getJoinTableResourceIdentifiers(type: string): { - joinTable: string - resourceKey: string - joinTableForeignKey: DiscountConditionJoinTableForeignKey - conditionTable: DiscountConditionResourceType - joinTableKey: string - } { - let conditionTable: DiscountConditionResourceType = DiscountConditionProduct + getJoinTableResourceIdentifiers(type: string): { + joinTable: string + resourceKey: string + joinTableForeignKey: DiscountConditionJoinTableForeignKey + conditionTable: DiscountConditionResourceType + joinTableKey: string + } { + let conditionTable: DiscountConditionResourceType = + DiscountConditionProduct - let joinTable = "product" - let joinTableForeignKey: DiscountConditionJoinTableForeignKey = - DiscountConditionJoinTableForeignKey.PRODUCT_ID - let joinTableKey = "id" + let joinTable = "product" + let joinTableForeignKey: DiscountConditionJoinTableForeignKey = + DiscountConditionJoinTableForeignKey.PRODUCT_ID + let joinTableKey = "id" - // On the joined table (e.g. `product`), what key should be match on - // (e.g `type_id` for product types and `id` for products) - let resourceKey + // On the joined table (e.g. `product`), what key should be match on + // (e.g `type_id` for product types and `id` for products) + let resourceKey - switch (type) { - case DiscountConditionType.PRODUCTS: { - resourceKey = "id" - joinTableForeignKey = DiscountConditionJoinTableForeignKey.PRODUCT_ID - joinTable = "product" + switch (type) { + case DiscountConditionType.PRODUCTS: { + resourceKey = "id" + joinTableForeignKey = DiscountConditionJoinTableForeignKey.PRODUCT_ID + joinTable = "product" - conditionTable = DiscountConditionProduct - break + conditionTable = DiscountConditionProduct + break + } + case DiscountConditionType.PRODUCT_TYPES: { + resourceKey = "type_id" + joinTableForeignKey = + DiscountConditionJoinTableForeignKey.PRODUCT_TYPE_ID + joinTable = "product" + + conditionTable = DiscountConditionProductType + break + } + case DiscountConditionType.PRODUCT_COLLECTIONS: { + resourceKey = "collection_id" + joinTableForeignKey = + DiscountConditionJoinTableForeignKey.PRODUCT_COLLECTION_ID + joinTable = "product" + + conditionTable = DiscountConditionProductCollection + break + } + case DiscountConditionType.PRODUCT_TAGS: { + joinTableKey = "product_id" + resourceKey = "product_tag_id" + joinTableForeignKey = + DiscountConditionJoinTableForeignKey.PRODUCT_TAG_ID + joinTable = "product_tags" + + conditionTable = DiscountConditionProductTag + break + } + case DiscountConditionType.CUSTOMER_GROUPS: { + joinTableKey = "customer_id" + resourceKey = "customer_group_id" + joinTable = "customer_group_customers" + joinTableForeignKey = + DiscountConditionJoinTableForeignKey.CUSTOMER_GROUP_ID + + conditionTable = DiscountConditionCustomerGroup + break + } + default: + break } - case DiscountConditionType.PRODUCT_TYPES: { - resourceKey = "type_id" - joinTableForeignKey = - DiscountConditionJoinTableForeignKey.PRODUCT_TYPE_ID - joinTable = "product" - conditionTable = DiscountConditionProductType - break + return { + joinTable, + joinTableKey, + resourceKey, + joinTableForeignKey, + conditionTable, } - case DiscountConditionType.PRODUCT_COLLECTIONS: { - resourceKey = "collection_id" - joinTableForeignKey = - DiscountConditionJoinTableForeignKey.PRODUCT_COLLECTION_ID - joinTable = "product" + }, - conditionTable = DiscountConditionProductCollection - break + async removeConditionResources( + id: string, + type: DiscountConditionType, + resourceIds: (string | { id: string })[] + ): Promise { + const { conditionTable, joinTableForeignKey } = + this.getJoinTableResourceIdentifiers(type) + + if (!conditionTable || !joinTableForeignKey) { + return Promise.resolve() } - case DiscountConditionType.PRODUCT_TAGS: { - joinTableKey = "product_id" - resourceKey = "product_tag_id" - joinTableForeignKey = - DiscountConditionJoinTableForeignKey.PRODUCT_TAG_ID - joinTable = "product_tags" - conditionTable = DiscountConditionProductTag - break - } - case DiscountConditionType.CUSTOMER_GROUPS: { - joinTableKey = "customer_id" - resourceKey = "customer_group_id" - joinTable = "customer_group_customers" - joinTableForeignKey = - DiscountConditionJoinTableForeignKey.CUSTOMER_GROUP_ID - - conditionTable = DiscountConditionCustomerGroup - break - } - default: - break - } - - return { - joinTable, - joinTableKey, - resourceKey, - joinTableForeignKey, - conditionTable, - } - } - - async removeConditionResources( - id: string, - type: DiscountConditionType, - resourceIds: (string | { id: string })[] - ): Promise { - const { conditionTable, joinTableForeignKey } = - this.getJoinTableResourceIdentifiers(type) - - if (!conditionTable || !joinTableForeignKey) { - return Promise.resolve() - } - - const idsToDelete = resourceIds.map((rId): string => { - return isString(rId) ? rId : rId.id - }) - return await this.createQueryBuilder() - .delete() - .from(conditionTable) - .where({ condition_id: id, [joinTableForeignKey]: In(idsToDelete) }) - .execute() - } - - async addConditionResources( - conditionId: string, - resourceIds: (string | { id: string })[], - type: DiscountConditionType, - overrideExisting = false - ): Promise< - ( - | DiscountConditionProduct - | DiscountConditionProductType - | DiscountConditionProductCollection - | DiscountConditionProductTag - | DiscountConditionCustomerGroup - )[] - > { - let toInsert: { condition_id: string; [x: string]: string }[] | [] = [] - - const { conditionTable, joinTableForeignKey } = - this.getJoinTableResourceIdentifiers(type) - - if (!conditionTable || !joinTableForeignKey) { - return Promise.resolve([]) - } - - const idsToInsert = resourceIds.map((rId): string => { - return isString(rId) ? rId : rId.id - }) - toInsert = idsToInsert.map((rId) => ({ - condition_id: conditionId, - [joinTableForeignKey]: rId, - })) - - const insertResult = await this.createQueryBuilder() - .insert() - .orIgnore(true) - .into(conditionTable) - .values(toInsert) - .execute() - - if (overrideExisting) { - await this.createQueryBuilder() + const idsToDelete = resourceIds.map((rId): string => { + return isString(rId) ? rId : rId.id + }) + return await this.createQueryBuilder() .delete() .from(conditionTable) - .where({ - condition_id: conditionId, - [joinTableForeignKey]: Not(In(idsToInsert)), - }) + .where({ condition_id: id, [joinTableForeignKey]: In(idsToDelete) }) .execute() - } + }, - return await this.manager - .createQueryBuilder(conditionTable, "discon") - .select() - .where(insertResult.identifiers) - .getMany() - } + async addConditionResources( + conditionId: string, + resourceIds: (string | { id: string })[], + type: DiscountConditionType, + overrideExisting = false + ): Promise< + ( + | DiscountConditionProduct + | DiscountConditionProductType + | DiscountConditionProductCollection + | DiscountConditionProductTag + | DiscountConditionCustomerGroup + )[] + > { + let toInsert: { condition_id: string; [x: string]: string }[] | [] = [] - async queryConditionTable({ type, condId, resourceId }): Promise { - const { - conditionTable, - joinTable, - joinTableForeignKey, - resourceKey, - joinTableKey, - } = this.getJoinTableResourceIdentifiers(type) + const { conditionTable, joinTableForeignKey } = + this.getJoinTableResourceIdentifiers(type) - return await this.manager - .createQueryBuilder(conditionTable, "dc") - .innerJoin( + if (!conditionTable || !joinTableForeignKey) { + return Promise.resolve([]) + } + + const idsToInsert = resourceIds.map((rId): string => { + return isString(rId) ? rId : rId.id + }) + toInsert = idsToInsert.map((rId) => ({ + condition_id: conditionId, + [joinTableForeignKey]: rId, + })) + + const insertResult = await this.createQueryBuilder() + .insert() + .orIgnore(true) + .into(conditionTable) + .values(toInsert) + .execute() + + if (overrideExisting) { + await this.createQueryBuilder() + .delete() + .from(conditionTable) + .where({ + condition_id: conditionId, + [joinTableForeignKey]: Not(In(idsToInsert)), + }) + .execute() + } + + return await this.manager + .createQueryBuilder(conditionTable, "discon") + .select() + .where(insertResult.identifiers) + .getMany() + }, + + async queryConditionTable({ type, condId, resourceId }): Promise { + const { + conditionTable, joinTable, - "resource", - `dc.${joinTableForeignKey} = resource.${resourceKey} and resource.${joinTableKey} = :resourceId `, - { - resourceId, + joinTableForeignKey, + resourceKey, + joinTableKey, + } = this.getJoinTableResourceIdentifiers(type) + + return await this.manager + .createQueryBuilder(conditionTable, "dc") + .innerJoin( + joinTable, + "resource", + `dc.${joinTableForeignKey} = resource.${resourceKey} and resource.${joinTableKey} = :resourceId `, + { + resourceId, + } + ) + .where(`dc.condition_id = :conditionId`, { + conditionId: condId, + }) + .getCount() + }, + + async isValidForProduct( + discountRuleId: string, + productId: string + ): Promise { + const discountConditions = await this.createQueryBuilder("discon") + .select(["discon.id", "discon.type", "discon.operator"]) + .where("discon.discount_rule_id = :discountRuleId", { + discountRuleId, + }) + .getMany() + + // in case of no discount conditions, we assume that the discount + // is valid for all + if (!discountConditions.length) { + return true + } + + // retrieve all conditions for each type where condition type id is in jointable (products, product_types, product_collections, product_tags) + // "E.g. for a given product condition, give me all products affected by it" + // for each of these types, we check: + // if condition operation is `in` and the query for conditions defined for the given type is empty, the discount is invalid + // if condition operation is `not_in` and the query for conditions defined for the given type is not empty, the discount is invalid + for (const condition of discountConditions) { + if (condition.type === DiscountConditionType.CUSTOMER_GROUPS) { + continue } - ) - .where(`dc.condition_id = :conditionId`, { - conditionId: condId, - }) - .getCount() - } - async isValidForProduct( - discountRuleId: string, - productId: string - ): Promise { - const discountConditions = await this.createQueryBuilder("discon") - .select(["discon.id", "discon.type", "discon.operator"]) - .where("discon.discount_rule_id = :discountRuleId", { - discountRuleId, - }) - .getMany() + const numConditions = await this.queryConditionTable({ + type: condition.type, + condId: condition.id, + resourceId: productId, + }) + + if ( + condition.operator === DiscountConditionOperator.IN && + numConditions === 0 + ) { + return false + } + + if ( + condition.operator === DiscountConditionOperator.NOT_IN && + numConditions > 0 + ) { + return false + } + } - // in case of no discount conditions, we assume that the discount - // is valid for all - if (!discountConditions.length) { return true - } + }, - // retrieve all conditions for each type where condition type id is in jointable (products, product_types, product_collections, product_tags) - // "E.g. for a given product condition, give me all products affected by it" - // for each of these types, we check: - // if condition operation is `in` and the query for conditions defined for the given type is empty, the discount is invalid - // if condition operation is `not_in` and the query for conditions defined for the given type is not empty, the discount is invalid - for (const condition of discountConditions) { - if (condition.type === DiscountConditionType.CUSTOMER_GROUPS) { - continue + async canApplyForCustomer( + discountRuleId: string, + customerId: string + ): Promise { + const discountConditions = await this.createQueryBuilder("discon") + .select(["discon.id", "discon.type", "discon.operator"]) + .where("discon.discount_rule_id = :discountRuleId", { + discountRuleId, + }) + .andWhere("discon.type = :type", { + type: DiscountConditionType.CUSTOMER_GROUPS, + }) + .getMany() + + // in case of no discount conditions, we assume that the discount + // is valid for all + if (!discountConditions.length) { + return true } - const numConditions = await this.queryConditionTable({ - type: condition.type, - condId: condition.id, - resourceId: productId, - }) + // retrieve conditions for customer groups + // for each customer group + // if condition operation is `in` and the query for customer group conditions is empty, the discount is invalid + // if condition operation is `not_in` and the query for customer group conditions is not empty, the discount is invalid + for (const condition of discountConditions) { + const numConditions = await this.queryConditionTable({ + type: "customer_groups", + condId: condition.id, + resourceId: customerId, + }) - if ( - condition.operator === DiscountConditionOperator.IN && - numConditions === 0 - ) { - return false + if ( + condition.operator === DiscountConditionOperator.IN && + numConditions === 0 + ) { + return false + } + + if ( + condition.operator === DiscountConditionOperator.NOT_IN && + numConditions > 0 + ) { + return false + } } - if ( - condition.operator === DiscountConditionOperator.NOT_IN && - numConditions > 0 - ) { - return false - } - } - - return true - } - - async canApplyForCustomer( - discountRuleId: string, - customerId: string - ): Promise { - const discountConditions = await this.createQueryBuilder("discon") - .select(["discon.id", "discon.type", "discon.operator"]) - .where("discon.discount_rule_id = :discountRuleId", { - discountRuleId, - }) - .andWhere("discon.type = :type", { - type: DiscountConditionType.CUSTOMER_GROUPS, - }) - .getMany() - - // in case of no discount conditions, we assume that the discount - // is valid for all - if (!discountConditions.length) { return true - } + }, + }) - // retrieve conditions for customer groups - // for each customer group - // if condition operation is `in` and the query for customer group conditions is empty, the discount is invalid - // if condition operation is `not_in` and the query for customer group conditions is not empty, the discount is invalid - for (const condition of discountConditions) { - const numConditions = await this.queryConditionTable({ - type: "customer_groups", - condId: condition.id, - resourceId: customerId, - }) - - if ( - condition.operator === DiscountConditionOperator.IN && - numConditions === 0 - ) { - return false - } - - if ( - condition.operator === DiscountConditionOperator.NOT_IN && - numConditions > 0 - ) { - return false - } - } - - return true - } -} +export default DiscountConditionRepository diff --git a/packages/medusa/src/repositories/discount-rule.ts b/packages/medusa/src/repositories/discount-rule.ts index 2acab73212..c8d232cba7 100644 --- a/packages/medusa/src/repositories/discount-rule.ts +++ b/packages/medusa/src/repositories/discount-rule.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { DiscountRule } from "../models/discount-rule" +import { DiscountRule } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(DiscountRule) -export class DiscountRuleRepository extends Repository {} +export const DiscountRuleRepository = dataSource.getRepository(DiscountRule) +export default DiscountRuleRepository diff --git a/packages/medusa/src/repositories/discount.ts b/packages/medusa/src/repositories/discount.ts index 1aa5cf7067..4b1ffc7782 100644 --- a/packages/medusa/src/repositories/discount.ts +++ b/packages/medusa/src/repositories/discount.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Discount } from "../models/discount" +import { Discount } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Discount) -export class DiscountRepository extends Repository {} +export const DiscountRepository = dataSource.getRepository(Discount) +export default DiscountRepository diff --git a/packages/medusa/src/repositories/draft-order.ts b/packages/medusa/src/repositories/draft-order.ts index 6ba65d1c8a..5a46ff2ac1 100644 --- a/packages/medusa/src/repositories/draft-order.ts +++ b/packages/medusa/src/repositories/draft-order.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { DraftOrder } from "../models/draft-order" +import { DraftOrder } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(DraftOrder) -export class DraftOrderRepository extends Repository {} +export const DraftOrderRepository = dataSource.getRepository(DraftOrder) +export default DraftOrderRepository diff --git a/packages/medusa/src/repositories/fulfillment-provider.ts b/packages/medusa/src/repositories/fulfillment-provider.ts index a65d8935a1..747ddecbea 100644 --- a/packages/medusa/src/repositories/fulfillment-provider.ts +++ b/packages/medusa/src/repositories/fulfillment-provider.ts @@ -1,6 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" -import { FulfillmentProvider } from "../models/fulfillment-provider" +import { FulfillmentProvider } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(FulfillmentProvider) -// eslint-disable-next-line max-len -export class FulfillmentProviderRepository extends Repository {} +export const FulfillmentProviderRepository = + dataSource.getRepository(FulfillmentProvider) +export default FulfillmentProviderRepository diff --git a/packages/medusa/src/repositories/fulfillment.ts b/packages/medusa/src/repositories/fulfillment.ts index f56117603f..174d4f50ad 100644 --- a/packages/medusa/src/repositories/fulfillment.ts +++ b/packages/medusa/src/repositories/fulfillment.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Fulfillment } from "../models/fulfillment" +import { Fulfillment } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Fulfillment) -export class FulfillmentRepository extends Repository {} +export const FulfillmentRepository = dataSource.getRepository(Fulfillment) +export default FulfillmentRepository diff --git a/packages/medusa/src/repositories/gift-card-transaction.ts b/packages/medusa/src/repositories/gift-card-transaction.ts index 3124ee58cb..b99e0aa3de 100644 --- a/packages/medusa/src/repositories/gift-card-transaction.ts +++ b/packages/medusa/src/repositories/gift-card-transaction.ts @@ -1,6 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" -import { GiftCardTransaction } from "../models/gift-card-transaction" +import { GiftCardTransaction } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(GiftCardTransaction) -// eslint-disable-next-line max-len -export class GiftCardTransactionRepository extends Repository {} +export const GiftCardTransactionRepository = + dataSource.getRepository(GiftCardTransaction) +export default GiftCardTransactionRepository diff --git a/packages/medusa/src/repositories/gift-card.ts b/packages/medusa/src/repositories/gift-card.ts index da6d6b3824..9c18368693 100644 --- a/packages/medusa/src/repositories/gift-card.ts +++ b/packages/medusa/src/repositories/gift-card.ts @@ -1,142 +1,40 @@ -import { flatten, groupBy, merge } from "lodash" -import { - Brackets, - EntityRepository, - FindManyOptions, - Repository, -} from "typeorm" -import { GiftCard } from "../models/gift-card" -import { ExtendedFindConfig, QuerySelector, Writable } from "../types/common" +import { FindOptionsWhere, ILike, Raw } from "typeorm" +import { GiftCard } from "../models" +import { ExtendedFindConfig } from "../types/common" +import { dataSource } from "../loaders/database" -@EntityRepository(GiftCard) -export class GiftCardRepository extends Repository { - public async findWithRelations( - relations: (keyof GiftCard | string)[] = [], - idsOrOptionsWithoutRelations: - | Omit, "relations"> - | string[] = {} - ): Promise<[GiftCard[], number]> { - let entities: GiftCard[] = [] - let count = 0 - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.findByIds(idsOrOptionsWithoutRelations) - count = idsOrOptionsWithoutRelations.length - } else { - const [results, resultCount] = await this.findAndCount( - idsOrOptionsWithoutRelations - ) - entities = results - count = resultCount - } - const entitiesIds = entities.map(({ id }) => id) - - const groupedRelations = {} - for (const rel of relations) { - const [topLevel] = rel.split(".") - if (groupedRelations[topLevel]) { - groupedRelations[topLevel].push(rel) - } else { - groupedRelations[topLevel] = [rel] - } - } - - const entitiesIdsWithRelations = await Promise.all( - Object.entries(groupedRelations).map(async ([_, rels]) => { - return this.findByIds(entitiesIds, { - select: ["id"], - relations: rels as string[], - }) - }) - ).then(flatten) - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) - - const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id") - return [ - Object.values(entitiesAndRelationsById).map((v) => merge({}, ...v)), - count, - ] - } - - protected async queryGiftCards( - q: string, - where: Partial>>, - rels: (keyof GiftCard | string)[], - shouldCount = false - ): Promise<[GiftCard[], number]> { - const qb = this.createQueryBuilder("gift_card") - .leftJoinAndSelect("gift_card.order", "order") - .select(["gift_card.id"]) - .where(where) - .andWhere( - new Brackets((qb) => { - return qb - .where(`gift_card.code ILIKE :q`, { q: `%${q}%` }) - .orWhere(`display_id::varchar(255) ILIKE :dId`, { dId: `${q}` }) - }) - ) - - let raw: GiftCard[] = [] - let count = 0 - if (shouldCount) { - const [results, resultCount] = await qb.getManyAndCount() - raw = results - count = resultCount - } else { - raw = await qb.getMany() - } - - const [results] = await this.findWithRelations( - rels, - raw.map((i) => i.id) - ) - - return [results, count] - } - - public async listGiftCardsAndCount( - inputQuery: ExtendedFindConfig>, - rels: (keyof GiftCard | string)[] = [], +export const GiftCardRepository = dataSource.getRepository(GiftCard).extend({ + async listGiftCardsAndCount( + query: ExtendedFindConfig, q?: string ): Promise<[GiftCard[], number]> { - const query = { ...inputQuery } + const query_ = { ...query } + query_.where = query_.where as FindOptionsWhere if (q) { - const where = query.where - delete where.id + delete query_.where.id - return await this.queryGiftCards(q, where, rels, true) - } - return await this.findWithRelations(rels, query) - } + query_.relations = query_.relations ?? {} + query_.relations.order = query_.relations.order ?? true - public async listGiftCards( - query: ExtendedFindConfig>, - rels: (keyof GiftCard | string)[] = [], - q?: string - ): Promise { - if (q) { - const where = query.where - delete where.id - - const [result] = await this.queryGiftCards(q, where, rels) - return result + query_.where = query_.where as FindOptionsWhere[] + query_.where = [ + { + ...query_.where, + code: ILike(`%${q}%`), + }, + { + ...query_.where, + order: { + display_id: Raw((alias) => `CAST(${alias} as varchar) ILike :q`, { + q: `%${q}%`, + }), + }, + }, + ] } - const [results] = await this.findWithRelations(rels, query) - return results - } - - public async findOneWithRelations( - relations: Array = [], - optionsWithoutRelations: Omit, "relations"> = {} - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const [result] = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - } -} + return await this.findAndCount(query_) + }, +}) +export default GiftCardRepository diff --git a/packages/medusa/src/repositories/idempotency-key.ts b/packages/medusa/src/repositories/idempotency-key.ts index c17a2c58d7..8521c21241 100644 --- a/packages/medusa/src/repositories/idempotency-key.ts +++ b/packages/medusa/src/repositories/idempotency-key.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { IdempotencyKey } from "../models/idempotency-key" +import { IdempotencyKey } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(IdempotencyKey) -export class IdempotencyKeyRepository extends Repository {} +export const IdempotencyKeyRepository = dataSource.getRepository(IdempotencyKey) +export default IdempotencyKeyRepository diff --git a/packages/medusa/src/repositories/image.ts b/packages/medusa/src/repositories/image.ts index fac2aad568..3334121acb 100644 --- a/packages/medusa/src/repositories/image.ts +++ b/packages/medusa/src/repositories/image.ts @@ -1,9 +1,9 @@ -import { EntityRepository, In, Repository } from "typeorm" -import { Image } from "../models/image" +import { Image } from "../models" +import { dataSource } from "../loaders/database" +import { In } from "typeorm" -@EntityRepository(Image) -export class ImageRepository extends Repository { - public async upsertImages(imageUrls: string[]) { +export const ImageRepository = dataSource.getRepository(Image).extend({ + async upsertImages(imageUrls: string[]) { const existingImages = await this.find({ where: { url: In(imageUrls), @@ -27,5 +27,6 @@ export class ImageRepository extends Repository { } return upsertedImgs - } -} + }, +}) +export default ImageRepository diff --git a/packages/medusa/src/repositories/invite.ts b/packages/medusa/src/repositories/invite.ts index 85f023a09b..e34aa397b5 100644 --- a/packages/medusa/src/repositories/invite.ts +++ b/packages/medusa/src/repositories/invite.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Invite } from "../models/invite" +import { Invite } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Invite) -export class InviteRepository extends Repository {} +export const InviteRepository = dataSource.getRepository(Invite) +export default InviteRepository diff --git a/packages/medusa/src/repositories/line-item-adjustment.ts b/packages/medusa/src/repositories/line-item-adjustment.ts index 2f73af275c..e99b7216b0 100644 --- a/packages/medusa/src/repositories/line-item-adjustment.ts +++ b/packages/medusa/src/repositories/line-item-adjustment.ts @@ -1,6 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" -import { LineItemAdjustment } from "../models/line-item-adjustment" +import { LineItemAdjustment } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(LineItemAdjustment) -// eslint-disable-next-line max-len -export class LineItemAdjustmentRepository extends Repository {} +export const LineItemAdjustmentRepository = + dataSource.getRepository(LineItemAdjustment) +export default LineItemAdjustmentRepository diff --git a/packages/medusa/src/repositories/line-item-tax-line.ts b/packages/medusa/src/repositories/line-item-tax-line.ts index 4e13b99070..503d417ace 100644 --- a/packages/medusa/src/repositories/line-item-tax-line.ts +++ b/packages/medusa/src/repositories/line-item-tax-line.ts @@ -1,38 +1,37 @@ -import { EntityRepository, Repository } from "typeorm" -import { LineItemTaxLine } from "../models/line-item-tax-line" +import { LineItemTaxLine } from "../models" import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" +import { dataSource } from "../loaders/database" -@EntityRepository(LineItemTaxLine) -export class LineItemTaxLineRepository extends Repository { - async upsertLines(lines: LineItemTaxLine[]): Promise { - const insertResult = await this.createQueryBuilder() - .insert() - .values(lines as QueryDeepPartialEntity[]) - .orUpdate({ - conflict_target: ["item_id", "code"], - overwrite: ["rate", "name", "updated_at"], - }) - .execute() +export const LineItemTaxLineRepository = dataSource + .getRepository(LineItemTaxLine) + .extend({ + async upsertLines(lines: LineItemTaxLine[]): Promise { + const insertResult = await this.createQueryBuilder() + .insert() + .values(lines as QueryDeepPartialEntity[]) + .orUpdate(["rate", "name", "updated_at"], ["item_id", "code"]) + .execute() - return insertResult.identifiers as LineItemTaxLine[] - } + return insertResult.identifiers as LineItemTaxLine[] + }, - async deleteForCart(cartId: string): Promise { - const qb = this.createQueryBuilder("line") - .select(["line.id"]) - .innerJoin("line_item", "i", "i.id = line.item_id") - .innerJoin( - "cart", - "c", - "i.cart_id = :cartId AND c.completed_at is NULL", - { cartId } - ) + async deleteForCart(cartId: string): Promise { + const qb = this.createQueryBuilder("line") + .select(["line.id"]) + .innerJoin("line_item", "i", "i.id = line.item_id") + .innerJoin( + "cart", + "c", + "i.cart_id = :cartId AND c.completed_at is NULL", + { cartId } + ) - const toDelete = await qb.getMany() + const toDelete = await qb.getMany() - await this.createQueryBuilder() - .delete() - .whereInIds(toDelete.map((d) => d.id)) - .execute() - } -} + await this.createQueryBuilder() + .delete() + .whereInIds(toDelete.map((d) => d.id)) + .execute() + }, + }) +export default LineItemTaxLineRepository diff --git a/packages/medusa/src/repositories/line-item.ts b/packages/medusa/src/repositories/line-item.ts index 20ce15c2ad..aa38e9587a 100644 --- a/packages/medusa/src/repositories/line-item.ts +++ b/packages/medusa/src/repositories/line-item.ts @@ -1,9 +1,8 @@ -import { EntityRepository, Repository } from "typeorm" import { LineItem } from "../models/line-item" import { ReturnItem } from "../models/return-item" +import { dataSource } from "../loaders/database" -@EntityRepository(LineItem) -export class LineItemRepository extends Repository { +export const LineItemRepository = dataSource.getRepository(LineItem).extend({ /** * Finds line items that are to be returned as part of the Return represented * by `returnId`. The function joins the associated ReturnItem and the @@ -27,5 +26,7 @@ export class LineItemRepository extends Repository { .where(`ri.return_id = :returnId`, { returnId }) return (await qb.getMany()) as (LineItem & { return_item: ReturnItem })[] - } -} + }, +}) + +export default LineItemRepository diff --git a/packages/medusa/src/repositories/money-amount.ts b/packages/medusa/src/repositories/money-amount.ts index 2906b8cc48..e427823278 100644 --- a/packages/medusa/src/repositories/money-amount.ts +++ b/packages/medusa/src/repositories/money-amount.ts @@ -1,20 +1,19 @@ import partition from "lodash/partition" import { Brackets, - EntityRepository, In, IsNull, Not, ObjectLiteral, - Repository, WhereExpressionBuilder, } from "typeorm" -import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" -import { MoneyAmount } from "../models/money-amount" +import { MoneyAmount } from "../models" import { PriceListPriceCreateInput, PriceListPriceUpdateInput, } from "../types/price-list" +import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" +import { dataSource } from "../loaders/database" type Price = Partial< Omit @@ -22,252 +21,253 @@ type Price = Partial< amount: number } -@EntityRepository(MoneyAmount) -export class MoneyAmountRepository extends Repository { - /** - * Will be removed in a future release. - * Use `deleteVariantPricesNotIn` instead. - * @deprecated - */ - public async findVariantPricesNotIn( - variantId: string, - prices: Price[] - ): Promise { - const pricesNotInPricesPayload = await this.createQueryBuilder() - .where({ +export const MoneyAmountRepository = dataSource + .getRepository(MoneyAmount) + .extend({ + async findVariantPricesNotIn( + variantId: string, + prices: Price[] + ): Promise { + const pricesNotInPricesPayload = await this.createQueryBuilder() + .where({ + variant_id: variantId, + price_list_id: IsNull(), + }) + .andWhere( + new Brackets((qb) => { + qb.where({ + currency_code: Not(In(prices.map((p) => p.currency_code))), + }).orWhere({ region_id: Not(In(prices.map((p) => p.region_id))) }) + }) + ) + .getMany() + return pricesNotInPricesPayload + }, + + async upsertVariantCurrencyPrice( + variantId: string, + price: Price + ): Promise { + let moneyAmount = await this.findOne({ + where: { + currency_code: price.currency_code, + variant_id: variantId, + region_id: IsNull(), + price_list_id: IsNull(), + }, + }) + + if (!moneyAmount) { + moneyAmount = this.create({ + ...price, + currency_code: price.currency_code?.toLowerCase(), + variant_id: variantId, + }) + } else { + moneyAmount.amount = price.amount + } + + return await this.save(moneyAmount) + }, + + async deleteVariantPricesNotIn( + variantId: string, + prices: Price[] + ): Promise { + const where = { variant_id: variantId, price_list_id: IsNull(), - }) - .andWhere( - new Brackets((qb) => { - qb.where({ - currency_code: Not(In(prices.map((p) => p.currency_code))), - }).orWhere({ region_id: Not(In(prices.map((p) => p.region_id))) }) + } + + const orWhere: ObjectLiteral[] = [] + + for (const price of prices) { + if (price.currency_code) { + orWhere.push( + { + currency_code: Not(price.currency_code), + }, + { + region_id: price.region_id ? Not(price.region_id) : Not(IsNull()), + currency_code: price.currency_code, + } + ) + } + + if (price.region_id) { + orWhere.push({ + region_id: Not(price.region_id), + }) + } + } + + await this.createQueryBuilder() + .delete() + .where(where) + .andWhere(orWhere) + .execute() + }, + + async addPriceListPrices( + priceListId: string, + prices: PriceListPriceCreateInput[], + overrideExisting = false + ): Promise { + const toInsert = prices.map((price) => + this.create({ + ...price, + price_list_id: priceListId, }) ) - .getMany() - return pricesNotInPricesPayload - } - public async deleteVariantPricesNotIn( - variantId: string, - prices: Price[] - ): Promise { - const where = { - variant_id: variantId, - price_list_id: IsNull(), - } + const insertResult = await this.createQueryBuilder() + .insert() + .orIgnore(true) + .into(MoneyAmount) + .values(toInsert as QueryDeepPartialEntity[]) + .execute() - const orWhere: ObjectLiteral[] = [] - - for (const price of prices) { - if (price.currency_code) { - orWhere.push( - { - currency_code: Not(price.currency_code), - }, - { - region_id: price.region_id ? Not(price.region_id) : Not(IsNull()), - currency_code: price.currency_code, - } - ) + if (overrideExisting) { + await this.createQueryBuilder() + .delete() + .from(MoneyAmount) + .where({ + price_list_id: priceListId, + id: Not(In(insertResult.identifiers.map((ma) => ma.id))), + }) + .execute() } - if (price.region_id) { - orWhere.push({ - region_id: Not(price.region_id), - }) - } - } + return await this.manager + .createQueryBuilder(MoneyAmount, "ma") + .select() + .where(insertResult.identifiers) + .getMany() + }, - await this.createQueryBuilder() - .delete() - .where(where) - .andWhere(orWhere) - .execute() - } - - public async upsertVariantCurrencyPrice( - variantId: string, - price: Price - ): Promise { - let moneyAmount = await this.findOne({ - where: { - currency_code: price.currency_code, - variant_id: variantId, - region_id: IsNull(), - price_list_id: IsNull(), - }, - }) - - if (!moneyAmount) { - moneyAmount = this.create({ - ...price, - currency_code: price.currency_code?.toLowerCase(), - variant_id: variantId, - }) - } else { - moneyAmount.amount = price.amount - } - - return await this.save(moneyAmount) - } - - public async addPriceListPrices( - priceListId: string, - prices: PriceListPriceCreateInput[], - overrideExisting = false - ): Promise { - const toInsert = prices.map((price) => - this.create({ - ...price, - price_list_id: priceListId, - }) - ) - - const insertResult = await this.createQueryBuilder() - .insert() - .orIgnore(true) - .into(MoneyAmount) - .values(toInsert as QueryDeepPartialEntity[]) - .execute() - - if (overrideExisting) { + async deletePriceListPrices( + priceListId: string, + moneyAmountIds: string[] + ): Promise { await this.createQueryBuilder() .delete() .from(MoneyAmount) - .where({ - price_list_id: priceListId, - id: Not(In(insertResult.identifiers.map((ma) => ma.id))), - }) + .where({ price_list_id: priceListId, id: In(moneyAmountIds) }) .execute() - } + }, - return await this.manager - .createQueryBuilder(MoneyAmount, "ma") - .select() - .where(insertResult.identifiers) - .getMany() - } + async findManyForVariantInPriceList( + variant_id: string, + price_list_id: string, + requiresPriceList = false + ): Promise<[MoneyAmount[], number]> { + const qb = this.createQueryBuilder("ma") + .leftJoinAndSelect("ma.price_list", "price_list") + .where("ma.variant_id = :variant_id", { variant_id }) - public async deletePriceListPrices( - priceListId: string, - moneyAmountIds: string[] - ): Promise { - await this.createQueryBuilder() - .delete() - .from(MoneyAmount) - .where({ price_list_id: priceListId, id: In(moneyAmountIds) }) - .execute() - } - - public async findManyForVariantInPriceList( - variant_id: string, - price_list_id: string, - requiresPriceList = false - ): Promise<[MoneyAmount[], number]> { - const qb = this.createQueryBuilder("ma") - .leftJoinAndSelect("ma.price_list", "price_list") - .where("ma.variant_id = :variant_id", { variant_id }) - - const getAndWhere = (subQb): WhereExpressionBuilder => { - const andWhere = subQb.where("ma.price_list_id = :price_list_id", { - price_list_id, - }) - if (!requiresPriceList) { - andWhere.orWhere("ma.price_list_id IS NULL") - } - return andWhere - } - - qb.andWhere(new Brackets(getAndWhere)) - - return await qb.getManyAndCount() - } - - public async findManyForVariantInRegion( - variant_id: string, - region_id?: string, - currency_code?: string, - customer_id?: string, - include_discount_prices?: boolean, - include_tax_inclusive_pricing = false - ): Promise<[MoneyAmount[], number]> { - const date = new Date() - - const qb = this.createQueryBuilder("ma") - .leftJoinAndSelect("ma.price_list", "price_list") - .where({ variant_id: variant_id }) - .andWhere("(ma.price_list_id is null or price_list.status = 'active')") - .andWhere("(price_list.ends_at is null OR price_list.ends_at > :date)", { - date: date.toUTCString(), - }) - .andWhere( - "(price_list.starts_at is null OR price_list.starts_at < :date)", - { - date: date.toUTCString(), - } - ) - - if (include_tax_inclusive_pricing) { - qb.leftJoin("ma.currency", "currency") - .leftJoin("ma.region", "region") - .addSelect(["currency.includes_tax", "region.includes_tax"]) - } - if (region_id || currency_code) { - qb.andWhere( - new Brackets((qb) => { - if (region_id && !currency_code) { - qb.where({ region_id: region_id }) - } - if (!region_id && currency_code) { - qb.where({ currency_code: currency_code }) - } - if (currency_code && region_id) { - qb.where({ region_id: region_id }).orWhere({ - currency_code: currency_code, - }) - } + const getAndWhere = (subQb): WhereExpressionBuilder => { + const andWhere = subQb.where("ma.price_list_id = :price_list_id", { + price_list_id, }) - ) - } else if (!customer_id && !include_discount_prices) { - qb.andWhere("price_list.id IS null") - } + if (!requiresPriceList) { + andWhere.orWhere("ma.price_list_id IS NULL") + } + return andWhere + } - if (customer_id) { - qb.leftJoin("price_list.customer_groups", "cgroup") - .leftJoin( - "customer_group_customers", - "cgc", - "cgc.customer_group_id = cgroup.id" + qb.andWhere(new Brackets(getAndWhere)) + + return await qb.getManyAndCount() + }, + + async findManyForVariantInRegion( + variant_id: string, + region_id?: string, + currency_code?: string, + customer_id?: string, + include_discount_prices?: boolean, + include_tax_inclusive_pricing = false + ): Promise<[MoneyAmount[], number]> { + const date = new Date() + + const qb = this.createQueryBuilder("ma") + .leftJoinAndSelect("ma.price_list", "price_list") + .where({ variant_id: variant_id }) + .andWhere("(ma.price_list_id is null or price_list.status = 'active')") + .andWhere( + "(price_list.ends_at is null OR price_list.ends_at > :date)", + { + date: date.toUTCString(), + } ) .andWhere( - "(cgc.customer_group_id is null OR cgc.customer_id = :customer_id)", + "(price_list.starts_at is null OR price_list.starts_at < :date)", { - customer_id, + date: date.toUTCString(), } ) - } else { - qb.leftJoin("price_list.customer_groups", "cgroup").andWhere( - "cgroup.id is null" + + if (include_tax_inclusive_pricing) { + qb.leftJoin("ma.currency", "currency") + .leftJoin("ma.region", "region") + .addSelect(["currency.includes_tax", "region.includes_tax"]) + } + if (region_id || currency_code) { + qb.andWhere( + new Brackets((qb) => { + if (region_id && !currency_code) { + qb.where({ region_id: region_id }) + } + if (!region_id && currency_code) { + qb.where({ currency_code: currency_code }) + } + if (currency_code && region_id) { + qb.where({ region_id: region_id }).orWhere({ + currency_code: currency_code, + }) + } + }) + ) + } else if (!customer_id && !include_discount_prices) { + qb.andWhere("price_list.id IS null") + } + + if (customer_id) { + qb.leftJoin("price_list.customer_groups", "cgroup") + .leftJoin( + "customer_group_customers", + "cgc", + "cgc.customer_group_id = cgroup.id" + ) + .andWhere( + "(cgc.customer_group_id is null OR cgc.customer_id = :customer_id)", + { + customer_id, + } + ) + } else { + qb.leftJoin("price_list.customer_groups", "cgroup").andWhere( + "cgroup.id is null" + ) + } + return await qb.getManyAndCount() + }, + + async updatePriceListPrices( + priceListId: string, + updates: PriceListPriceUpdateInput[] + ): Promise { + const [existingPrices, newPrices] = partition( + updates, + (update) => update.id ) - } - return await qb.getManyAndCount() - } - public async updatePriceListPrices( - priceListId: string, - updates: PriceListPriceUpdateInput[] - ): Promise { - const [existingPrices, newPrices] = partition( - updates, - (update) => update.id - ) + const newPriceEntities = newPrices.map((price) => + this.create({ ...price, price_list_id: priceListId }) + ) - const newPriceEntities = newPrices.map((price) => - this.create({ ...price, price_list_id: priceListId }) - ) + return await this.save([...existingPrices, ...newPriceEntities]) + }, + }) - return await this.save([...existingPrices, ...newPriceEntities]) - } -} +export default MoneyAmountRepository diff --git a/packages/medusa/src/repositories/note.ts b/packages/medusa/src/repositories/note.ts index 1e3065c417..3392992374 100644 --- a/packages/medusa/src/repositories/note.ts +++ b/packages/medusa/src/repositories/note.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Note } from "../models/note" +import { Note } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Note) -export class NoteRepository extends Repository {} +export const NoteRepository = dataSource.getRepository(Note) +export default NoteRepository diff --git a/packages/medusa/src/repositories/notification-provider.ts b/packages/medusa/src/repositories/notification-provider.ts index 9fb5df8f86..c948cc8502 100644 --- a/packages/medusa/src/repositories/notification-provider.ts +++ b/packages/medusa/src/repositories/notification-provider.ts @@ -1,6 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" import { NotificationProvider } from "../models/notification-provider" +import { dataSource } from "../loaders/database" -@EntityRepository(NotificationProvider) -// eslint-disable-next-line max-len -export class NotificationProviderRepository extends Repository {} +export const NotificationProviderRepository = + dataSource.getRepository(NotificationProvider) +export default NotificationProviderRepository diff --git a/packages/medusa/src/repositories/notification.ts b/packages/medusa/src/repositories/notification.ts index beea98ae58..4decb78619 100644 --- a/packages/medusa/src/repositories/notification.ts +++ b/packages/medusa/src/repositories/notification.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Notification } from "../models/notification" +import { Notification } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Notification) -export class NotificationRepository extends Repository {} +export const NotificationRepository = dataSource.getRepository(Notification) +export default NotificationRepository diff --git a/packages/medusa/src/repositories/oauth.ts b/packages/medusa/src/repositories/oauth.ts index dd9bc509e5..e6b3cfc9da 100644 --- a/packages/medusa/src/repositories/oauth.ts +++ b/packages/medusa/src/repositories/oauth.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Oauth } from "../models/oauth" +import { Oauth } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Oauth) -export class OauthRepository extends Repository {} +export const OauthRepository = dataSource.getRepository(Oauth) +export default OauthRepository diff --git a/packages/medusa/src/repositories/order-edit.ts b/packages/medusa/src/repositories/order-edit.ts index 8b90fc7b3f..67f3073edc 100644 --- a/packages/medusa/src/repositories/order-edit.ts +++ b/packages/medusa/src/repositories/order-edit.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { OrderEdit } from "../models" +import { OrderEdit } from "../models/order-edit" +import { dataSource } from "../loaders/database" -@EntityRepository(OrderEdit) -export class OrderEditRepository extends Repository {} +export const OrderEditRepository = dataSource.getRepository(OrderEdit) +export default OrderEditRepository diff --git a/packages/medusa/src/repositories/order-item-change.ts b/packages/medusa/src/repositories/order-item-change.ts index ea78b61e48..19b99c5497 100644 --- a/packages/medusa/src/repositories/order-item-change.ts +++ b/packages/medusa/src/repositories/order-item-change.ts @@ -1,6 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" +import { OrderItemChange } from "../models" +import { dataSource } from "../loaders/database" -import { OrderItemChange } from "../models/order-item-change" - -@EntityRepository(OrderItemChange) -export class OrderItemChangeRepository extends Repository {} +export const OrderItemChangeRepository = + dataSource.getRepository(OrderItemChange) +export default OrderItemChangeRepository diff --git a/packages/medusa/src/repositories/order.ts b/packages/medusa/src/repositories/order.ts index ce1477de19..7321bcd2f8 100644 --- a/packages/medusa/src/repositories/order.ts +++ b/packages/medusa/src/repositories/order.ts @@ -1,21 +1,22 @@ import { flatten, groupBy, map, merge } from "lodash" -import { EntityRepository, FindManyOptions, Repository } from "typeorm" +import { FindManyOptions, FindOptionsRelations, In } from "typeorm" import { Order } from "../models" +import { buildLegacyFieldsListFrom } from "../utils" +import { dataSource } from "../loaders/database" const ITEMS_REL_NAME = "items" const REGION_REL_NAME = "region" -@EntityRepository(Order) -export class OrderRepository extends Repository { - public async findWithRelations( - relations: string[] = [], +export const OrderRepository = dataSource.getRepository(Order).extend({ + async findWithRelations( + relations: FindOptionsRelations = {}, optionsWithoutRelations: Omit, "relations"> = {} ): Promise { const entities = await this.find(optionsWithoutRelations) const entitiesIds = entities.map(({ id }) => id) const groupedRelations: { [topLevel: string]: string[] } = {} - for (const rel of relations) { + for (const rel of buildLegacyFieldsListFrom(relations)) { const [topLevel] = rel.split(".") if (groupedRelations[topLevel]) { groupedRelations[topLevel].push(rel) @@ -27,7 +28,8 @@ export class OrderRepository extends Repository { const entitiesIdsWithRelations = await Promise.all( Object.entries(groupedRelations).map(async ([topLevel, rels]) => { // If top level is region or items then get deleted region as well - return this.findByIds(entitiesIds, { + return this.find({ + where: { id: In(entitiesIds) }, select: ["id"], relations: rels, withDeleted: @@ -41,10 +43,10 @@ export class OrderRepository extends Repository { const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id") return map(entities, (e) => merge({}, ...entitiesAndRelationsById[e.id])) - } + }, - public async findOneWithRelations( - relations: string[] = [], + async findOneWithRelations( + relations: FindOptionsRelations = {}, optionsWithoutRelations: Omit, "relations"> = {} ): Promise { // Limit 1 @@ -55,5 +57,7 @@ export class OrderRepository extends Repository { optionsWithoutRelations ) return result[0] - } -} + }, +}) + +export default OrderRepository diff --git a/packages/medusa/src/repositories/payment-collection.ts b/packages/medusa/src/repositories/payment-collection.ts index 99a5190ef3..2eea4a7bb6 100644 --- a/packages/medusa/src/repositories/payment-collection.ts +++ b/packages/medusa/src/repositories/payment-collection.ts @@ -1,63 +1,65 @@ import { MedusaError } from "medusa-core-utils" import { PaymentCollection } from "./../models/payment-collection" -import { EntityRepository, Repository } from "typeorm" import { FindConfig } from "../types/common" +import { dataSource } from "../loaders/database" -@EntityRepository(PaymentCollection) -// eslint-disable-next-line max-len -export class PaymentCollectionRepository extends Repository { - async getPaymentCollectionIdBySessionId( - sessionId: string, - config: FindConfig = {} - ): Promise { - const paymentCollection = await this.find({ - join: { - alias: "payment_col", - innerJoin: { payment_sessions: "payment_col.payment_sessions" }, - }, - where: (qb) => { - qb.where( - "payment_col_payment_sessions.payment_session_id = :sessionId", - { sessionId } +export const PaymentCollectionRepository = dataSource + .getRepository(PaymentCollection) + .extend({ + async getPaymentCollectionIdBySessionId( + sessionId: string, + config: FindConfig = {} + ): Promise { + const paymentCollection = await this.find({ + join: { + alias: "payment_col", + innerJoin: { payment_sessions: "payment_col.payment_sessions" }, + }, + where: { + payment_sessions: { + id: sessionId, + }, + }, + relations: config.relations, + select: config.select, + }) + + if (!paymentCollection.length) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `Payment collection related to Payment Session id ${sessionId} was not found` ) - }, - relations: config.relations, - select: config.select, - }) + } - if (!paymentCollection.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Payment collection related to Payment Session id ${sessionId} was not found` - ) - } + return paymentCollection[0] + }, - return paymentCollection[0] - } + async getPaymentCollectionIdByPaymentId( + paymentId: string, + config: FindConfig = {} + ): Promise { + const paymentCollection = await this.find({ + join: { + alias: "payment_col", + innerJoin: { payments: "payment_col.payments" }, + }, + where: { + payments: { + id: paymentId, + }, + }, + relations: config.relations, + select: config.select, + }) - async getPaymentCollectionIdByPaymentId( - paymentId: string, - config: FindConfig = {} - ): Promise { - const paymentCollection = await this.find({ - join: { - alias: "payment_col", - innerJoin: { payments: "payment_col.payments" }, - }, - where: (qb) => { - qb.where("payment_col_payments.payment_id = :paymentId", { paymentId }) - }, - relations: config.relations, - select: config.select, - }) + if (!paymentCollection.length) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `Payment collection related to Payment id ${paymentId} was not found` + ) + } - if (!paymentCollection.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `Payment collection related to Payment id ${paymentId} was not found` - ) - } - - return paymentCollection[0] - } -} + return paymentCollection[0] + }, + }) +export default PaymentCollectionRepository diff --git a/packages/medusa/src/repositories/payment-provider.ts b/packages/medusa/src/repositories/payment-provider.ts index 7237b3e48b..7de45e4538 100644 --- a/packages/medusa/src/repositories/payment-provider.ts +++ b/packages/medusa/src/repositories/payment-provider.ts @@ -1,5 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" -import { PaymentProvider } from "../models/payment-provider" +import { PaymentProvider } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(PaymentProvider) -export class PaymentProviderRepository extends Repository {} +export const PaymentProviderRepository = + dataSource.getRepository(PaymentProvider) +export default PaymentProviderRepository diff --git a/packages/medusa/src/repositories/payment-session.ts b/packages/medusa/src/repositories/payment-session.ts index 9e526f4d68..aee2f90505 100644 --- a/packages/medusa/src/repositories/payment-session.ts +++ b/packages/medusa/src/repositories/payment-session.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { PaymentSession } from "../models/payment-session" +import { PaymentSession } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(PaymentSession) -export class PaymentSessionRepository extends Repository {} +export const PaymentSessionRepository = dataSource.getRepository(PaymentSession) +export default PaymentSessionRepository diff --git a/packages/medusa/src/repositories/payment.ts b/packages/medusa/src/repositories/payment.ts index 642cf5fb03..06957536f6 100644 --- a/packages/medusa/src/repositories/payment.ts +++ b/packages/medusa/src/repositories/payment.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Payment } from "../models/payment" +import { Payment } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Payment) -export class PaymentRepository extends Repository {} +export const PaymentRepository = dataSource.getRepository(Payment) +export default PaymentRepository diff --git a/packages/medusa/src/repositories/price-list.ts b/packages/medusa/src/repositories/price-list.ts index 30d3b9d215..78afeffeb0 100644 --- a/packages/medusa/src/repositories/price-list.ts +++ b/packages/medusa/src/repositories/price-list.ts @@ -1,127 +1,40 @@ -import { groupBy, map } from "lodash" -import { - Brackets, - EntityRepository, - FindManyOptions, - FindOperator, - Repository, -} from "typeorm" -import { PriceList } from "../models/price-list" +import { FindOptionsWhere, ILike } from "typeorm" +import { PriceList } from "../models" import { CustomFindOptions, ExtendedFindConfig } from "../types/common" -import { FilterablePriceListProps } from "../types/price-list" +import { dataSource } from "../loaders/database" export type PriceListFindOptions = CustomFindOptions< PriceList, "status" | "type" > -@EntityRepository(PriceList) -export class PriceListRepository extends Repository { - public async getFreeTextSearchResultsAndCount( - q: string, - options: PriceListFindOptions = { where: {} }, - groups: FindOperator, - relations: string[] = [] +export const PriceListRepository = dataSource.getRepository(PriceList).extend({ + async listAndCount( + query: ExtendedFindConfig, + q?: string ): Promise<[PriceList[], number]> { - options.where = options.where ?? {} + const query_ = { ...query } - const qb = this.createQueryBuilder("price_list") - .leftJoinAndSelect("price_list.customer_groups", "customer_group") - .select(["price_list.id"]) - .where(options.where) - .andWhere( - new Brackets((qb) => { - qb.where(`price_list.description ILIKE :q`, { q: `%${q}%` }) - .orWhere(`price_list.name ILIKE :q`, { q: `%${q}%` }) - .orWhere(`customer_group.name ILIKE :q`, { q: `%${q}%` }) - }) - ) - .skip(options.skip) - .take(options.take) + if (q) { + query_.where = query_.where as FindOptionsWhere + delete query_.where.description + delete query_.where.name - if (groups) { - qb.andWhere("group.id IN (:...ids)", { ids: groups.value }) - } - - const [results, count] = await qb.getManyAndCount() - - const price_lists = await this.findWithRelations( - relations, - results.map((r) => r.id) - ) - - return [price_lists, count] - } - - public async findWithRelations( - relations: string[] = [], - idsOrOptionsWithoutRelations: - | Omit, "relations"> - | string[] = {} - ): Promise { - let entities - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.findByIds(idsOrOptionsWithoutRelations) - } else { - entities = await this.find(idsOrOptionsWithoutRelations) - } - const groupedRelations: Record = {} - for (const relation of relations) { - const [topLevel] = relation.split(".") - if (groupedRelations[topLevel]) { - groupedRelations[topLevel].push(relation) - } else { - groupedRelations[topLevel] = [relation] + query_.where.description = ILike(`%${q}%`) + query_.where.name = ILike(`%${q}%`) + query_.where.customer_groups = { + name: ILike(`%${q}%`), } } - const entitiesIds = entities.map(({ id }) => id) - const entitiesIdsWithRelations = await Promise.all( - Object.values(groupedRelations).map(async (relations: string[]) => { - return this.findByIds(entitiesIds, { - select: ["id"], - relations: relations as string[], - }) - }) - ).then((entitiesIdsWithRelations) => entitiesIdsWithRelations.flat()) - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) - const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id") - return map(entitiesAndRelationsById, (entityAndRelations) => - this.merge(this.create(), ...entityAndRelations) - ) - } + return await this.findAndCount({ + ...query_, + relations: { + customer_groups: true, + }, + relationLoadStrategy: "query", + }) + }, +}) - public async findOneWithRelations( - relations: (keyof PriceList)[] = [], - options: Omit, "relations"> = {} - ): Promise { - options.take = 1 - - return (await this.findWithRelations(relations, options))?.pop() - } - - async listAndCount( - query: ExtendedFindConfig, - groups: FindOperator - ): Promise<[PriceList[], number]> { - const qb = this.createQueryBuilder("price_list") - .where(query.where) - .skip(query.skip) - .take(query.take) - - if (groups) { - qb.leftJoinAndSelect("price_list.customer_groups", "group").andWhere( - "group.id IN (:...ids)", - { ids: groups.value } - ) - } - - if (query.relations?.length) { - query.relations.forEach((rel) => { - qb.leftJoinAndSelect(`price_list.${rel}`, rel) - }) - } - - return await qb.getManyAndCount() - } -} +export default PriceListRepository diff --git a/packages/medusa/src/repositories/product-category.ts b/packages/medusa/src/repositories/product-category.ts index a16760fc84..fd6204bb9a 100644 --- a/packages/medusa/src/repositories/product-category.ts +++ b/packages/medusa/src/repositories/product-category.ts @@ -1,120 +1,127 @@ import { - EntityRepository, - TreeRepository, Brackets, + FindOptionsWhere, ILike, - getConnection, DeleteResult, In, } from "typeorm" import { ProductCategory } from "../models/product-category" -import { ExtendedFindConfig, Selector, QuerySelector } from "../types/common" +import { ExtendedFindConfig, QuerySelector } from "../types/common" +import { dataSource } from "../loaders/database" +import { buildLegacyFieldsListFrom } from "../utils" -@EntityRepository(ProductCategory) -export class ProductCategoryRepository extends TreeRepository { - public async getFreeTextSearchResultsAndCount( - options: ExtendedFindConfig> = { - where: {}, - }, - q: string | undefined, - treeScope: QuerySelector = {} - ): Promise<[ProductCategory[], number]> { - const entityName = "product_category" - const options_ = { ...options } - const relations = options_.relations || [] +export const ProductCategoryRepository = dataSource + .getTreeRepository(ProductCategory) + .extend({ + async getFreeTextSearchResultsAndCount( + options: ExtendedFindConfig = { + where: {}, + }, + q: string | undefined, + treeScope: QuerySelector = {} + ): Promise<[ProductCategory[], number]> { + const entityName = "product_category" + const options_ = { ...options } + options_.where = options_.where as FindOptionsWhere - const selectStatements = (relationName: string): string[] => { - const modelColumns = this.manager.connection - .getMetadata(ProductCategory) - .ownColumns.map((column) => column.propertyName) + const legacySelect = buildLegacyFieldsListFrom(options_.select) + const legacyRelations = buildLegacyFieldsListFrom(options_.relations) - return (options_.select || modelColumns).map((column) => { - return `${relationName}.${column}` - }) - } - - const queryBuilder = this.createQueryBuilder(entityName) - .select(selectStatements(entityName)) - .skip(options_.skip) - .take(options_.take) - - if (q) { - delete options_.where?.name - delete options_.where?.handle - - queryBuilder.where( - new Brackets((bracket) => { - bracket - .where({ name: ILike(`%${q}%`) }) - .orWhere({ handle: ILike(`%${q}%`) }) - }) - ) - } - - queryBuilder.andWhere(options_.where) - - const includedTreeRelations: string[] = relations.filter((rel) => - ProductCategory.treeRelations.includes(rel) - ) - - includedTreeRelations.forEach((treeRelation) => { - const treeWhere = Object.entries(treeScope) - .map((entry) => `${treeRelation}.${entry[0]} = :${entry[0]}`) - .join(" AND ") - - queryBuilder - .leftJoin( - `${entityName}.${treeRelation}`, - treeRelation, - treeWhere, - treeScope + const selectStatements = (relationName: string): string[] => { + const modelColumns = this.metadata.ownColumns.map( + (column) => column.propertyName ) - .addSelect(selectStatements(treeRelation)) - }) + const selectColumns = legacySelect.length ? legacySelect : modelColumns - const nonTreeRelations: string[] = relations.filter( - (rel) => !ProductCategory.treeRelations.includes(rel) - ) + return selectColumns.map((column) => { + return `${relationName}.${column}` + }) + } - nonTreeRelations.forEach((relation) => { - queryBuilder.leftJoinAndSelect(`${entityName}.${relation}`, relation) - }) + const queryBuilder = this.createQueryBuilder(entityName) + .select(selectStatements(entityName)) + .skip(options_.skip) + .take(options_.take) - if (options_.withDeleted) { - queryBuilder.withDeleted() - } + if (q) { + delete options_.where?.name + delete options_.where?.handle - return await queryBuilder.getManyAndCount() - } + queryBuilder.where( + new Brackets((bracket) => { + bracket + .where({ name: ILike(`%${q}%`) }) + .orWhere({ handle: ILike(`%${q}%`) }) + }) + ) + } - async addProducts( - productCategoryId: string, - productIds: string[] - ): Promise { - await this.createQueryBuilder() - .insert() - .into(ProductCategory.productCategoryProductJoinTable) - .values( - productIds.map((id) => ({ - product_category_id: productCategoryId, - product_id: id, - })) + queryBuilder.andWhere(options_.where) + + const includedTreeRelations: string[] = legacyRelations.filter((rel) => + ProductCategory.treeRelations.includes(rel) ) - .orIgnore() - .execute() - } - async removeProducts( - productCategoryId: string, - productIds: string[] - ): Promise { - return await this.createQueryBuilder() - .delete() - .from(ProductCategory.productCategoryProductJoinTable) - .where({ - product_category_id: productCategoryId, - product_id: In(productIds), + includedTreeRelations.forEach((treeRelation) => { + const treeWhere = Object.entries(treeScope) + .map((entry) => `${treeRelation}.${entry[0]} = :${entry[0]}`) + .join(" AND ") + + queryBuilder + .leftJoin( + `${entityName}.${treeRelation}`, + treeRelation, + treeWhere, + treeScope + ) + .addSelect(selectStatements(treeRelation)) }) - .execute() - } -} + + const nonTreeRelations: string[] = legacyRelations.filter( + (rel) => !ProductCategory.treeRelations.includes(rel) + ) + + nonTreeRelations.forEach((relation) => { + queryBuilder.leftJoinAndSelect(`${entityName}.${relation}`, relation) + }) + + if (options_.withDeleted) { + queryBuilder.withDeleted() + } + + return await queryBuilder.getManyAndCount() + }, + + async addProducts( + productCategoryId: string, + productIds: string[] + ): Promise { + await this.createQueryBuilder() + .insert() + .into(ProductCategory.productCategoryProductJoinTable) + .values( + productIds.map((id) => ({ + product_category_id: productCategoryId, + product_id: id, + })) + ) + .orIgnore() + .execute() + }, + + async removeProducts( + productCategoryId: string, + productIds: string[] + ): Promise { + return await this.createQueryBuilder() + .delete() + .from(ProductCategory.productCategoryProductJoinTable) + .where({ + product_category_id: productCategoryId, + product_id: In(productIds), + }) + .execute() + }, + }) + +export default ProductCategoryRepository \ No newline at end of file diff --git a/packages/medusa/src/repositories/product-collection.ts b/packages/medusa/src/repositories/product-collection.ts index 4311690a48..cd7e44b28a 100644 --- a/packages/medusa/src/repositories/product-collection.ts +++ b/packages/medusa/src/repositories/product-collection.ts @@ -1,36 +1,24 @@ -import { EntityRepository, Repository } from "typeorm" import { ProductCollection } from "../models" -import { ExtendedFindConfig, Selector } from "../types/common" +import { dataSource } from "../loaders/database" +import { ExtendedFindConfig } from "../types/common" -@EntityRepository(ProductCollection) // eslint-disable-next-line max-len -export class ProductCollectionRepository extends Repository { - async findAndCountByDiscountConditionId( - conditionId: string, - query: ExtendedFindConfig> - ): Promise<[ProductCollection[], number]> { - const qb = this.createQueryBuilder("pc") - - if (query?.select) { - qb.select(query.select.map((select) => `pc.${select}`)) - } - - if (query.skip) { - qb.skip(query.skip) - } - - if (query.take) { - qb.take(query.take) - } - - return await qb - .where(query.where) - .innerJoin( - "discount_condition_product_collection", - "dc_pc", - `dc_pc.product_collection_id = pc.id AND dc_pc.condition_id = :dcId`, - { dcId: conditionId } - ) - .getManyAndCount() - } -} +export const ProductCollectionRepository = dataSource + .getRepository(ProductCollection) + .extend({ + async findAndCountByDiscountConditionId( + conditionId: string, + query: ExtendedFindConfig + ): Promise<[ProductCollection[], number]> { + return await this.createQueryBuilder("pc") + .setFindOptions(query) + .innerJoin( + "discount_condition_product_collection", + "dc_pc", + `dc_pc.product_collection_id = pc.id AND dc_pc.condition_id = :dcId`, + { dcId: conditionId } + ) + .getManyAndCount() + }, + }) +export default ProductCollectionRepository diff --git a/packages/medusa/src/repositories/product-option-value.ts b/packages/medusa/src/repositories/product-option-value.ts index 828436cfad..5c1316ff63 100644 --- a/packages/medusa/src/repositories/product-option-value.ts +++ b/packages/medusa/src/repositories/product-option-value.ts @@ -1,6 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" -import { ProductOptionValue } from "../models/product-option-value" +import { ProductOptionValue } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(ProductOptionValue) -// eslint-disable-next-line max-len -export class ProductOptionValueRepository extends Repository {} +export const ProductOptionValueRepository = + dataSource.getRepository(ProductOptionValue) +export default ProductOptionValueRepository diff --git a/packages/medusa/src/repositories/product-option.ts b/packages/medusa/src/repositories/product-option.ts index eef6f08088..ba6715507c 100644 --- a/packages/medusa/src/repositories/product-option.ts +++ b/packages/medusa/src/repositories/product-option.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { ProductOption } from "../models/product-option" +import { ProductOption } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(ProductOption) -export class ProductOptionRepository extends Repository {} +export const ProductOptionRepository = dataSource.getRepository(ProductOption) +export default ProductOptionRepository diff --git a/packages/medusa/src/repositories/product-tag.ts b/packages/medusa/src/repositories/product-tag.ts index 97f616052a..dc32d84807 100644 --- a/packages/medusa/src/repositories/product-tag.ts +++ b/packages/medusa/src/repositories/product-tag.ts @@ -1,6 +1,7 @@ -import { EntityRepository, In, Repository } from "typeorm" +import { In } from "typeorm" import { ProductTag } from "../models/product-tag" -import { ExtendedFindConfig, Selector } from "../types/common" +import { ExtendedFindConfig } from "../types/common" +import { dataSource } from "../loaders/database" type UpsertTagsInput = (Partial & { value: string @@ -12,7 +13,7 @@ type ProductTagSelector = Partial & { } export type DefaultWithoutRelations = Omit< - ExtendedFindConfig, + ExtendedFindConfig, "relations" > @@ -22,11 +23,12 @@ export type FindWithoutRelationsOptions = DefaultWithoutRelations & { } } -@EntityRepository(ProductTag) -export class ProductTagRepository extends Repository { - public async listTagsByUsage(count = 10): Promise { - return await this.query( - ` +export const ProductTagRepository = dataSource + .getRepository(ProductTag) + .extend({ + async listTagsByUsage(count = 10): Promise { + return await this.query( + ` SELECT id, COUNT(pts.product_tag_id) as usage_count, pt.value FROM product_tag pt LEFT JOIN product_tags pts ON pt.id = pts.product_tag_id @@ -34,63 +36,52 @@ export class ProductTagRepository extends Repository { ORDER BY usage_count DESC LIMIT $1 `, - [count] - ) - } - - public async upsertTags(tags: UpsertTagsInput): Promise { - const tagsValues = tags.map((tag) => tag.value) - const existingTags = await this.find({ - where: { - value: In(tagsValues), - }, - }) - const existingTagsMap = new Map( - existingTags.map<[string, ProductTag]>((tag) => [tag.value, tag]) - ) - - const upsertedTags: ProductTag[] = [] - - for (const tag of tags) { - const aTag = existingTagsMap.get(tag.value) - if (aTag) { - upsertedTags.push(aTag) - } else { - const newTag = this.create(tag) - const savedTag = await this.save(newTag) - upsertedTags.push(savedTag) - } - } - - return upsertedTags - } - - async findAndCountByDiscountConditionId( - conditionId: string, - query: ExtendedFindConfig> - ) { - const qb = this.createQueryBuilder("pt") - - if (query?.select) { - qb.select(query.select.map((select) => `pt.${select}`)) - } - - if (query.skip) { - qb.skip(query.skip) - } - - if (query.take) { - qb.take(query.take) - } - - return await qb - .where(query.where) - .innerJoin( - "discount_condition_product_tag", - "dc_pt", - `dc_pt.product_tag_id = pt.id AND dc_pt.condition_id = :dcId`, - { dcId: conditionId } + [count] ) - .getManyAndCount() - } -} + }, + + async upsertTags(tags: UpsertTagsInput): Promise { + const tagsValues = tags.map((tag) => tag.value) + const existingTags = await this.find({ + where: { + value: In(tagsValues), + }, + }) + const existingTagsMap = new Map( + existingTags.map<[string, ProductTag]>((tag) => [tag.value, tag]) + ) + + const upsertedTags: ProductTag[] = [] + + for (const tag of tags) { + const aTag = existingTagsMap.get(tag.value) + if (aTag) { + upsertedTags.push(aTag) + } else { + const newTag = this.create(tag) + const savedTag = await this.save(newTag) + upsertedTags.push(savedTag) + } + } + + return upsertedTags + }, + + async findAndCountByDiscountConditionId( + conditionId: string, + query: ExtendedFindConfig + ) { + return await this.createQueryBuilder("pt") + .where(query.where) + .setFindOptions(query) + .innerJoin( + "discount_condition_product_tag", + "dc_pt", + `dc_pt.product_tag_id = pt.id AND dc_pt.condition_id = :dcId`, + { dcId: conditionId } + ) + .getManyAndCount() + }, + }) + +export default ProductTagRepository diff --git a/packages/medusa/src/repositories/product-tax-rate.ts b/packages/medusa/src/repositories/product-tax-rate.ts index db166fb5b6..6f477946b3 100644 --- a/packages/medusa/src/repositories/product-tax-rate.ts +++ b/packages/medusa/src/repositories/product-tax-rate.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { ProductTaxRate } from "../models/product-tax-rate" +import { ProductTaxRate } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(ProductTaxRate) -export class ProductTaxRateRepository extends Repository {} +export const ProductTaxRateRepository = dataSource.getRepository(ProductTaxRate) +export default ProductTaxRateRepository diff --git a/packages/medusa/src/repositories/product-type.ts b/packages/medusa/src/repositories/product-type.ts index 4c036c1612..0b9afcdbe1 100644 --- a/packages/medusa/src/repositories/product-type.ts +++ b/packages/medusa/src/repositories/product-type.ts @@ -1,58 +1,47 @@ -import { EntityRepository, Repository } from "typeorm" import { ProductType } from "../models/product-type" -import { ExtendedFindConfig, Selector } from "../types/common" +import { ExtendedFindConfig } from "../types/common" +import { dataSource } from "../loaders/database" type UpsertTypeInput = Partial & { value: string } -@EntityRepository(ProductType) -export class ProductTypeRepository extends Repository { - async upsertType(type?: UpsertTypeInput): Promise { - if (!type) { - return null - } +export const ProductTypeRepository = dataSource + .getRepository(ProductType) + .extend({ + async upsertType(type?: UpsertTypeInput): Promise { + if (!type) { + return null + } - const existing = await this.findOne({ - where: { value: type.value }, - }) + const existing = await this.findOne({ + where: { value: type.value }, + }) - if (existing) { - return existing - } + if (existing) { + return existing + } - const created = this.create({ - value: type.value, - }) - return await this.save(created) - } + const created = this.create({ + value: type.value, + }) + return await this.save(created) + }, - async findAndCountByDiscountConditionId( - conditionId: string, - query: ExtendedFindConfig> - ): Promise<[ProductType[], number]> { - const qb = this.createQueryBuilder("pt") - - if (query?.select) { - qb.select(query.select.map((select) => `pt.${select}`)) - } - - if (query.skip) { - qb.skip(query.skip) - } - - if (query.take) { - qb.take(query.take) - } - - return await qb - .where(query.where) - .innerJoin( - "discount_condition_product_type", - "dc_pt", - `dc_pt.product_type_id = pt.id AND dc_pt.condition_id = :dcId`, - { dcId: conditionId } - ) - .getManyAndCount() - } -} + async findAndCountByDiscountConditionId( + conditionId: string, + query: ExtendedFindConfig + ): Promise<[ProductType[], number]> { + return await this.createQueryBuilder("pt") + .where(query.where) + .setFindOptions(query) + .innerJoin( + "discount_condition_product_type", + "dc_pt", + `dc_pt.product_type_id = pt.id AND dc_pt.condition_id = :dcId`, + { dcId: conditionId } + ) + .getManyAndCount() + }, + }) +export default ProductTypeRepository diff --git a/packages/medusa/src/repositories/product-variant.ts b/packages/medusa/src/repositories/product-variant.ts index 5f4fe82e08..523d654ffc 100644 --- a/packages/medusa/src/repositories/product-variant.ts +++ b/packages/medusa/src/repositories/product-variant.ts @@ -1,254 +1,12 @@ -import { - EntityRepository, - FindConditions, - FindManyOptions, - OrderByCondition, - Repository, -} from "typeorm" -import { flatten, groupBy, map, merge } from "lodash" +import { FindManyOptions } from "typeorm" import { ProductVariant } from "../models/product-variant" +import { FindOptionsOrder } from "typeorm/find-options/FindOptionsOrder" +import { dataSource } from "../loaders/database" export type FindWithRelationsOptions = FindManyOptions & { - order?: OrderByCondition + order?: FindOptionsOrder withDeleted?: boolean } -@EntityRepository(ProductVariant) -export class ProductVariantRepository extends Repository { - private mergeEntitiesWithRelations( - entitiesAndRelations: Array> - ): ProductVariant[] { - const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id") - return map(entitiesAndRelationsById, (entityAndRelations) => - merge({}, ...entityAndRelations) - ) - } - - private async queryProductsVariants( - optionsWithoutRelations: FindWithRelationsOptions, - shouldCount = false - ): Promise<[ProductVariant[], number]> { - let qb = this.createQueryBuilder("pv") - .select(["pv.id"]) - .skip(optionsWithoutRelations.skip) - .take(optionsWithoutRelations.take) - - qb = optionsWithoutRelations.where - ? qb.where(optionsWithoutRelations.where) - : qb - - qb = optionsWithoutRelations.order - ? qb.orderBy(optionsWithoutRelations.order) - : qb - - if (optionsWithoutRelations.withDeleted) { - qb = qb.withDeleted() - } - - let entities: ProductVariant[] - let count = 0 - if (shouldCount) { - const result = await qb.getManyAndCount() - entities = result[0] - count = result[1] - } else { - entities = await qb.getMany() - } - - return [entities, count] - } - - private getGroupedRelations(relations: Array): { - [toplevel: string]: string[] - } { - const groupedRelations: { [toplevel: string]: string[] } = {} - for (const rel of relations) { - const [topLevel] = rel.split(".") - if (groupedRelations[topLevel]) { - groupedRelations[topLevel].push(rel) - } else { - groupedRelations[topLevel] = [rel] - } - } - - return groupedRelations - } - - private async queryProductVariantsWithIds( - entityIds: string[], - groupedRelations: { [toplevel: string]: string[] }, - withDeleted = false - ): Promise { - const entitiesIdsWithRelations = await Promise.all( - Object.entries(groupedRelations).map(async ([toplevel, rels]) => { - const querybuilder = this.createQueryBuilder("pv").leftJoinAndSelect( - `pv.${toplevel}`, - toplevel - ) - - for (const rel of rels) { - const [_, rest] = rel.split(".") - if (!rest) { - continue - } - // Regex matches all '.' except the rightmost - querybuilder.leftJoinAndSelect( - rel.replace(/\.(?=[^.]*\.)/g, "__"), - rel.replace(".", "__") - ) - } - - if (withDeleted) { - querybuilder - .where("pv.id IN (:...entitiesIds)", { - entitiesIds: entityIds, - }) - .withDeleted() - } else { - querybuilder.where( - "pv.deleted_at IS NULL AND pv.id IN (:...entitiesIds)", - { - entitiesIds: entityIds, - } - ) - } - - return querybuilder.getMany() - }) - ).then(flatten) - - return entitiesIdsWithRelations - } - - public async findWithRelationsAndCount( - relations: string[] = [], - idsOrOptionsWithoutRelations: FindWithRelationsOptions | string[] = { - where: {}, - }, - withDeleted?: boolean - ): Promise<[ProductVariant[], number]> { - let count: number - let entities: ProductVariant[] - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.findByIds(idsOrOptionsWithoutRelations, { - withDeleted: withDeleted ?? false, - }) - count = entities.length - } else { - const result = await this.queryProductsVariants( - idsOrOptionsWithoutRelations, - true - ) - entities = result[0] - count = result[1] - } - const entitiesIds = entities.map(({ id }) => id) - - if (entitiesIds.length === 0) { - // no need to continue - return [[], count] - } - - if (relations.length === 0) { - const options = { ...idsOrOptionsWithoutRelations } - - // Since we are finding by the ids that have been retrieved above and those ids are already - // applying skip/take. Remove those options to avoid getting no results - if (typeof options === "object") { - delete (options as FindWithRelationsOptions).skip - delete (options as FindWithRelationsOptions).take - } - - const toReturn = await this.findByIds( - entitiesIds, - options as FindConditions - ) - return [toReturn, count] - } - - const groupedRelations = this.getGroupedRelations( - relations as (keyof ProductVariant)[] - ) - const entitiesIdsWithRelations = await this.queryProductVariantsWithIds( - entitiesIds, - groupedRelations, - withDeleted - ) - - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) - const entitiesToReturn = - this.mergeEntitiesWithRelations(entitiesAndRelations) - - return [entitiesToReturn, count] - } - - public async findWithRelations( - relations: string[] = [], - idsOrOptionsWithoutRelations: FindWithRelationsOptions | string[] = {}, - withDeleted = false - ): Promise { - let entities: ProductVariant[] - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.findByIds(idsOrOptionsWithoutRelations, { - withDeleted, - }) - } else { - const result = await this.queryProductsVariants( - idsOrOptionsWithoutRelations, - false - ) - entities = result[0] - } - const entitiesIds = entities.map(({ id }) => id) - - if (entitiesIds.length === 0) { - // no need to continue - return [] - } - - if (relations.length === 0) { - const options = { ...idsOrOptionsWithoutRelations } - - // Since we are finding by the ids that have been retrieved above and those ids are already - // applying skip/take. Remove those options to avoid getting no results - if (typeof options === "object") { - delete (options as FindWithRelationsOptions).skip - delete (options as FindWithRelationsOptions).take - } - - return await this.findByIds( - entitiesIds, - options as FindConditions - ) - } - - const groupedRelations = this.getGroupedRelations( - relations as (keyof ProductVariant)[] - ) - const entitiesIdsWithRelations = await this.queryProductVariantsWithIds( - entitiesIds, - groupedRelations, - withDeleted - ) - - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) - const entitiesToReturn = - this.mergeEntitiesWithRelations(entitiesAndRelations) - - return entitiesToReturn - } - - public async findOneWithRelations( - relations: Array = [], - optionsWithoutRelations: FindWithRelationsOptions = { where: {} } - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const result = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - } -} +export const ProductVariantRepository = dataSource.getRepository(ProductVariant) +export default ProductVariantRepository diff --git a/packages/medusa/src/repositories/product.ts b/packages/medusa/src/repositories/product.ts index 5b60858ad3..a07a5f6fe5 100644 --- a/packages/medusa/src/repositories/product.ts +++ b/packages/medusa/src/repositories/product.ts @@ -1,116 +1,209 @@ -import { flatten, groupBy, map, merge } from "lodash" import { - Brackets, - EntityRepository, FindOperator, + FindOptionsWhere, + ILike, In, - Repository, + SelectQueryBuilder, } from "typeorm" -import { PriceList, Product, ProductCategory, SalesChannel } from "../models" -import { - ExtendedFindConfig, - Selector, - WithRequiredProperty, -} from "../types/common" -import { applyOrdering } from "../utils/repository" +import { Product, ProductCategory } from "../models" +import { ExtendedFindConfig } from "../types/common" +import { dataSource } from "../loaders/database" +import { isObject } from "../utils" +import { ProductFilterOptions } from "../types/product" -export type ProductSelector = Omit, "tags"> & { - tags: FindOperator -} +export const ProductRepository = dataSource.getRepository(Product).extend({ + async bulkAddToCollection( + productIds: string[], + collectionId: string + ): Promise { + await this.createQueryBuilder() + .update(Product) + .set({ collection_id: collectionId }) + .where({ id: In(productIds) }) + .execute() -export type DefaultWithoutRelations = Omit< - ExtendedFindConfig, - "relations" -> + return this.findByIds(productIds) + }, -export type FindWithoutRelationsOptions = DefaultWithoutRelations & { - where: DefaultWithoutRelations["where"] & { - price_list_id?: FindOperator - sales_channel_id?: FindOperator - category_id?: { - value: string[] - } - include_category_children?: boolean - discount_condition_id?: string - } -} + async bulkRemoveFromCollection( + productIds: string[], + collectionId: string + ): Promise { + await this.createQueryBuilder() + .update(Product) + .set({ collection_id: null }) + .where({ id: In(productIds), collection_id: collectionId }) + .execute() -@EntityRepository(Product) -export class ProductRepository extends Repository { - private mergeEntitiesWithRelations( - entitiesAndRelations: Array> - ): Product[] { - const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id") - return map(entitiesAndRelationsById, (entityAndRelations) => - merge({}, ...entityAndRelations) + return this.findByIds(productIds) + }, + + async isProductInSalesChannels( + id: string, + salesChannelIds: string[] + ): Promise { + return ( + (await this.createQueryBuilder("product") + .leftJoin( + "product.sales_channels", + "sales_channels", + "sales_channels.id IN (:...salesChannelIds)", + { salesChannelIds } + ) + .getCount()) > 0 ) - } + }, - private async queryProducts( - optionsWithoutRelations: FindWithoutRelationsOptions, - shouldCount = false + async findAndCount( + options: ExtendedFindConfig, + q?: string ): Promise<[Product[], number]> { + const queryBuilder = await this.prepareQueryBuilder_(options, q) + return await queryBuilder.getManyAndCount() + }, + + async findOne( + options: ExtendedFindConfig + ): Promise { + const queryBuilder = await this.prepareQueryBuilder_(options) + return await queryBuilder.getOne() + }, + + async prepareQueryBuilder_( + options: ExtendedFindConfig, + q?: string + ): Promise> { + const options_ = { ...options } + const productAlias = "product" + const queryBuilder = this.createQueryBuilder(productAlias) - const tags = optionsWithoutRelations?.where?.tags - delete optionsWithoutRelations?.where?.tags + // TODO: https://github.com/typeorm/typeorm/issues/9719 waiting an answer before being able to set it to `query` + // Therefore use query when there is only an ordering by the product entity otherwise fallback to join. + // In other word, if the order depth is more than 1 then use join otherwise use query + /* const orderFieldsCollectionPointSeparated = buildLegacyFieldsListFrom( + options.order ?? {} + ) + const isDepth1 = !orderFieldsCollectionPointSeparated.some( + (field) => field.indexOf(".") !== -1 + ) + options_.relationLoadStrategy = isDepth1 ? "query" : "join"*/ + options_.relationLoadStrategy = "join" - const price_lists = optionsWithoutRelations?.where?.price_list_id - delete optionsWithoutRelations?.where?.price_list_id + options_.relations = options_.relations ?? {} + options_.where = options_.where as FindOptionsWhere - const sales_channels = optionsWithoutRelations?.where?.sales_channel_id - delete optionsWithoutRelations?.where?.sales_channel_id + // Add explicit ordering for variant ranking on the variants join directly + // The constraint if there is any will be applied by the options_ + if (options_.relations.variants && !isObject(options_.order?.variants)) { + options_.order = options_.order ?? {} + options_.order.variants = { + variant_rank: "ASC", + } + /* // The query strategy, as explain at the top of the function, does not select the column from the separated query + // It is not possible to order with that strategy at the moment and, we are waiting for an answer from the typeorm team + options_.relationLoadStrategy = "join" + queryBuilder.leftJoinAndSelect(`${productAlias}.variants`, "variants") - const categories = optionsWithoutRelations?.where?.category_id - delete optionsWithoutRelations?.where?.category_id + options_.order = options_.order ?? {} - const include_category_children = - optionsWithoutRelations?.where?.include_category_children - delete optionsWithoutRelations?.where?.include_category_children - - const discount_condition_id = - optionsWithoutRelations?.where?.discount_condition_id - delete optionsWithoutRelations?.where?.discount_condition_id - - const qb = this.createQueryBuilder(productAlias) - .select([`${productAlias}.id`]) - .skip(optionsWithoutRelations.skip) - .take(optionsWithoutRelations.take) - - if (optionsWithoutRelations.where) { - qb.where(optionsWithoutRelations.where) - } - - if (tags) { - qb.leftJoin(`${productAlias}.tags`, "tags").andWhere( - `tags.id IN (:...tag_ids)`, - { - tag_ids: tags.value, + if (!isObject(options_.order.variants)) { + options_.order.variants = { + variant_rank: "ASC", } - ) + }*/ } - if (price_lists) { - qb.leftJoin(`${productAlias}.variants`, "variants") - .leftJoin("variants.prices", "prices") - .andWhere("prices.price_list_id IN (:...price_list_ids)", { - price_list_ids: price_lists.value, + if (options_.where.price_list_id) { + /* options_.relations.variants = { + ...(isObject(options_.relations.variants) + ? options_.relations.variants + : {}), + prices: true, + } + + const priceListIds = ( + options_.where.price_list_id as FindOperator + ).value + delete options_.where.price_list_id + + options_.where.variants = { + ...(isObject(options_.where.variants) ? options_.where.variants : {}), + prices: [ + { + price_list_id: In(priceListIds), + }, + ], + }*/ + const priceListIds = ( + options_.where.price_list_id as FindOperator + ).value + delete options_.where.price_list_id + + queryBuilder + .leftJoin(`${productAlias}.variants`, "variants") + .leftJoin("variants.prices", "ma") + .andWhere("ma.price_list_id IN (:...price_list_ids)", { + price_list_ids: priceListIds, }) } - if (sales_channels) { - qb.innerJoin( + if (options_.where.tags) { + const joinMethod = options_.relations.tags + ? queryBuilder.leftJoinAndSelect.bind(queryBuilder) + : queryBuilder.leftJoin.bind(queryBuilder) + + const tagIds = (options_.where.tags as FindOperator).value + + // For an unknown reason, the implementation of the SelectQueryBuilder.setFindOptions -> buildWhere + // Only check if it is a find operator MoreThan or LessThan. Otherwise, it has to be a relation of + // isManyToOne or isOneToOne in order to be valid. Otherwise, it throws `This relation isn't supported by given find operator` + // We might need to wait for an update or open a PR around that subject + + joinMethod(`${productAlias}.tags`, "tags").andWhere( + `tags.id IN (:...tag_ids)`, + { + tag_ids: tagIds, + } + ) + + delete options_.where.tags + } + + if (options_.where.sales_channel_id) { + const joinMethod = options_.relations.sales_channel_id + ? queryBuilder.innerJoinAndSelect.bind(queryBuilder) + : queryBuilder.innerJoin.bind(queryBuilder) + + const scIds = (options_.where.sales_channel_id as FindOperator) + .value + + // Same comment as in the tags if block above + inner join is only doable using the query builder and not the options + + joinMethod( `${productAlias}.sales_channels`, "sales_channels", "sales_channels.id IN (:...sales_channels_ids)", - { sales_channels_ids: sales_channels.value } + { + sales_channels_ids: scIds, + } ) + + delete options_.where.sales_channel_id } - if (categories) { - let categoryIds = categories.value + if (options_.where.category_id) { + const includeCategoryChildren = + options_.where.include_category_children || false + const joinMethod = options_.relations.category_id + ? queryBuilder.innerJoinAndSelect.bind(queryBuilder) + : queryBuilder.innerJoin.bind(queryBuilder) - if (include_category_children) { + let categoryIds = (options_.where.category_id as FindOperator) + .value + + // Same comment as in the tags if block above + inner join is only doable using the query builder and not the options + if (includeCategoryChildren) { const categoryRepository = this.manager.getTreeRepository(ProductCategory) const categories = await categoryRepository.find({ @@ -139,406 +232,75 @@ export class ProductRepository extends Repository { } } - if (categoryIds.length) { - qb.innerJoin( - `${productAlias}.categories`, - "categories", - "categories.id IN (:...categoryIds)", - { categoryIds } - ) - } - } - - if (discount_condition_id) { - qb.innerJoin( - "discount_condition_product", - "dc_product", - `dc_product.product_id = ${productAlias}.id AND dc_product.condition_id = :dcId`, - { dcId: discount_condition_id } - ) - } - - const joinedWithPriceLists = !!price_lists - applyOrdering({ - repository: this, - order: optionsWithoutRelations.order ?? {}, - qb, - alias: productAlias, - shouldJoin: (relation) => relation !== "prices" || !joinedWithPriceLists, - }) - - if (optionsWithoutRelations.withDeleted) { - qb.withDeleted() - } - - let entities: Product[] - let count = 0 - if (shouldCount) { - const result = await qb.getManyAndCount() - entities = result[0] - count = result[1] - } else { - entities = await qb.getMany() - } - - return [entities, count] - } - - private getGroupedRelations(relations: string[]): { - [toplevel: string]: string[] - } { - const groupedRelations: { [toplevel: string]: string[] } = {} - for (const rel of relations) { - const [topLevel] = rel.split(".") - if (groupedRelations[topLevel]) { - groupedRelations[topLevel].push(rel) - } else { - groupedRelations[topLevel] = [rel] - } - } - - return groupedRelations - } - - private async queryProductsWithIds( - entityIds: string[], - groupedRelations: { [toplevel: string]: string[] }, - withDeleted = false, - select: (keyof Product)[] = [], - order: { [column: string]: "ASC" | "DESC" } = {} - ): Promise { - const entitiesIdsWithRelations = await Promise.all( - Object.entries(groupedRelations).map(async ([toplevel, rels]) => { - let querybuilder = this.createQueryBuilder("products") - - if (select && select.length) { - querybuilder.select(select.map((f) => `products.${f}`)) - } - - if (toplevel === "variants") { - querybuilder = querybuilder.leftJoinAndSelect( - `products.${toplevel}`, - toplevel, - "variants.deleted_at IS NULL" - ) - - if (!Object.keys(order).some((key) => key.startsWith("variants"))) { - // variant_rank being select false, apply the filter here directly - querybuilder.addOrderBy(`${toplevel}.variant_rank`, "ASC") - } - } else { - querybuilder = querybuilder.leftJoinAndSelect( - `products.${toplevel}`, - toplevel - ) - } - - for (const rel of rels) { - const [_, rest] = rel.split(".") - if (!rest) { - continue - } - // Regex matches all '.' except the rightmost - querybuilder = querybuilder.leftJoinAndSelect( - rel.replace(/\.(?=[^.]*\.)/g, "__"), - rel.replace(".", "__") - ) - } - - if (withDeleted) { - querybuilder = querybuilder - .where("products.id IN (:...entitiesIds)", { - entitiesIds: entityIds, - }) - .withDeleted() - } else { - querybuilder = querybuilder.where( - "products.deleted_at IS NULL AND products.id IN (:...entitiesIds)", - { - entitiesIds: entityIds, - } - ) - } - - return querybuilder.getMany() - }) - ).then(flatten) - - return entitiesIdsWithRelations - } - - public async findWithRelationsAndCount( - relations: string[] = [], - idsOrOptionsWithoutRelations: FindWithoutRelationsOptions = { where: {} } - ): Promise<[Product[], number]> { - let count: number - let entities: Product[] - - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.findByIds(idsOrOptionsWithoutRelations, { - withDeleted: idsOrOptionsWithoutRelations.withDeleted ?? false, - }) - count = entities.length - } else { - const result = await this.queryProducts( - idsOrOptionsWithoutRelations, - true - ) - entities = result[0] - count = result[1] - } - const entitiesIds = entities.map(({ id }) => id) - - if (entitiesIds.length === 0) { - // no need to continue - return [[], count] - } - - if (relations.length === 0) { - const options = { ...idsOrOptionsWithoutRelations } - - // Since we are finding by the ids that have been retrieved above and those ids are already - // applying skip/take. Remove those options to avoid getting no results - delete options.skip - delete options.take - - const toReturn = await this.findByIds(entitiesIds, options) - return [toReturn, toReturn.length] - } - - const groupedRelations = this.getGroupedRelations(relations) - const entitiesIdsWithRelations = await this.queryProductsWithIds( - entitiesIds, - groupedRelations, - idsOrOptionsWithoutRelations.withDeleted, - idsOrOptionsWithoutRelations.select, - idsOrOptionsWithoutRelations.order - ) - - const entitiesAndRelations = groupBy(entitiesIdsWithRelations, "id") - const entitiesToReturn = map(entitiesIds, (id) => - merge({}, ...entitiesAndRelations[id]) - ) - - return [entitiesToReturn, count] - } - - public async findWithRelations( - relations: string[] = [], - idsOrOptionsWithoutRelations: FindWithoutRelationsOptions | string[] = { - where: {}, - }, - withDeleted = false - ): Promise { - let entities: Product[] - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.findByIds(idsOrOptionsWithoutRelations, { - withDeleted, - }) - } else { - const result = await this.queryProducts( - idsOrOptionsWithoutRelations, - false - ) - entities = result[0] - } - const entitiesIds = entities.map(({ id }) => id) - - if (entitiesIds.length === 0) { - // no need to continue - return [] - } - - if ( - relations.length === 0 && - !Array.isArray(idsOrOptionsWithoutRelations) - ) { - return await this.findByIds(entitiesIds, idsOrOptionsWithoutRelations) - } - - const groupedRelations = this.getGroupedRelations(relations) - const entitiesIdsWithRelations = await this.queryProductsWithIds( - entitiesIds, - groupedRelations, - withDeleted - ) - - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) - const entitiesToReturn = - this.mergeEntitiesWithRelations(entitiesAndRelations) - - return entitiesToReturn - } - - public async findOneWithRelations( - relations: string[] = [], - optionsWithoutRelations: FindWithoutRelationsOptions = { where: {} } - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const result = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - } - - public async bulkAddToCollection( - productIds: string[], - collectionId: string - ): Promise { - await this.createQueryBuilder() - .update(Product) - .set({ collection_id: collectionId }) - .where({ id: In(productIds) }) - .execute() - - return this.findByIds(productIds) - } - - public async bulkRemoveFromCollection( - productIds: string[], - collectionId: string - ): Promise { - await this.createQueryBuilder() - .update(Product) - .set({ collection_id: null }) - .where({ id: In(productIds), collection_id: collectionId }) - .execute() - - return this.findByIds(productIds) - } - - public async getFreeTextSearchResultsAndCount( - q: string, - options: FindWithoutRelationsOptions = { where: {} }, - relations: string[] = [] - ): Promise<[Product[], number]> { - const productAlias = "product" - const pricesAlias = "prices" - const variantsAlias = "variants" - const collectionAlias = "collection" - const tagsAlias = "tags" - - const tags = options.where.tags - delete options.where.tags - - const price_lists = options.where.price_list_id - delete options.where.price_list_id - - const sales_channels = options.where.sales_channel_id - delete options.where.sales_channel_id - - const discount_condition_id = options.where.discount_condition_id - delete options.where.discount_condition_id - - const cleanedOptions = this._cleanOptions(options) - - let qb = this.createQueryBuilder(`${productAlias}`) - .leftJoinAndSelect(`${productAlias}.variants`, variantsAlias) - .leftJoinAndSelect(`${productAlias}.collection`, `${collectionAlias}`) - .select([`${productAlias}.id`]) - .where(cleanedOptions.where) - .andWhere( - new Brackets((qb) => { - qb.where(`${productAlias}.description ILIKE :q`, { q: `%${q}%` }) - .orWhere(`${productAlias}.title ILIKE :q`, { q: `%${q}%` }) - .orWhere(`${variantsAlias}.title ILIKE :q`, { q: `%${q}%` }) - .orWhere(`${variantsAlias}.sku ILIKE :q`, { q: `%${q}%` }) - .orWhere(`${collectionAlias}.title ILIKE :q`, { q: `%${q}%` }) - }) - ) - .skip(cleanedOptions.skip) - .take(cleanedOptions.take) - - if (discount_condition_id) { - qb.innerJoin( - "discount_condition_product", - "dc_product", - `dc_product.product_id = ${productAlias}.id AND dc_product.condition_id = :dcId`, - { dcId: discount_condition_id } - ) - } - - if (tags) { - qb.leftJoin(`${productAlias}.tags`, tagsAlias).andWhere( - `${tagsAlias}.id IN (:...tag_ids)`, + joinMethod( + `${productAlias}.categories`, + "categories", + "categories.id IN (:...categoryIds)", { - tag_ids: tags.value, + categoryIds, } ) + + delete options_.where.category_id } - if (price_lists) { - const variantPricesAlias = `${variantsAlias}_prices` - qb.leftJoin(`${productAlias}.variants`, variantPricesAlias) - .leftJoin(`${variantPricesAlias}.prices`, pricesAlias) - .andWhere(`${pricesAlias}.price_list_id IN (:...price_list_ids)`, { - price_list_ids: price_lists.value, - }) - } + delete options_.where.include_category_children - if (sales_channels) { - qb.innerJoin( - `${productAlias}.sales_channels`, - "sales_channels", - "sales_channels.id IN (:...sales_channels_ids)", - { sales_channels_ids: sales_channels.value } + if (options_.where.discount_condition_id) { + // inner join is only doable using the query builder and not the options + + queryBuilder.innerJoin( + "discount_condition_product", + "dc_product", + `dc_product.product_id = product.id AND dc_product.condition_id = :dcId`, + { dcId: options_.where.discount_condition_id } ) + + delete options_.where.discount_condition_id + } + // TODO: move back to the service layer + if (q) { + options_.relations = options_.relations ?? {} + options_.relations.variants = options_.relations.variants ?? true + options_.relations.collection = options_.relations.collection ?? true + + options_.where = [ + { + ...options_.where, + description: ILike(`%${q}%`), + }, + { + ...options_.where, + title: ILike(`%${q}%`), + }, + { + ...options_.where, + variants: { + title: ILike(`%${q}%`), + }, + }, + { + ...options_.where, + variants: { + sku: ILike(`%${q}%`), + }, + }, + { + ...options_.where, + collection: { + title: ILike(`%${q}%`), + }, + }, + ] } - const joinedWithTags = !!tags - const joinedWithPriceLists = !!price_lists - applyOrdering({ - repository: this, - order: options.order ?? {}, - qb, - alias: productAlias, - shouldJoin: (relation) => - relation !== variantsAlias && - (relation !== pricesAlias || !joinedWithPriceLists) && - (relation !== tagsAlias || !joinedWithTags), - }) - - if (cleanedOptions.withDeleted) { - qb = qb.withDeleted() + if (options_.withDeleted) { + queryBuilder.withDeleted() } - const [results, count] = await qb.getManyAndCount() - const orderedResultsSet = new Set(results.map((p) => p.id)) - - const products = await this.findWithRelations( - relations, - [...orderedResultsSet], - cleanedOptions.withDeleted - ) - const productsMap = new Map(products.map((p) => [p.id, p])) - - // Looping through the orderedResultsSet in order to maintain the original order and assign the data returned by findWithRelations - const orderedProducts: Product[] = [] - orderedResultsSet.forEach((id) => { - orderedProducts.push(productsMap.get(id)!) - }) - - return [orderedProducts, count] - } - - public async isProductInSalesChannels( - id: string, - salesChannelIds: string[] - ): Promise { - return ( - (await this.createQueryBuilder("product") - .leftJoin( - "product.sales_channels", - "sales_channels", - "sales_channels.id IN (:...salesChannelIds)", - { salesChannelIds } - ) - .getCount()) > 0 - ) - } + queryBuilder.setFindOptions(options_) + return queryBuilder + }, /** * Upserts shipping profile for products @@ -546,7 +308,7 @@ export class ProductRepository extends Repository { * @param shippingProfileId ID of shipping profile to assign to products * @returns updated products */ - public async upsertShippingProfile( + async upsertShippingProfile( productIds: string[], shippingProfileId: string ): Promise { @@ -557,30 +319,7 @@ export class ProductRepository extends Repository { .execute() return await this.findByIds(productIds) - } + }, +}) - private _cleanOptions( - options: FindWithoutRelationsOptions - ): WithRequiredProperty { - const where = options.where ?? {} - if ("description" in where) { - delete where.description - } - if ("title" in where) { - delete where.title - } - - if ("price_list_id" in where) { - delete where?.price_list_id - } - - if ("discount_condition_id" in where) { - delete where?.discount_condition_id - } - - return { - ...options, - where, - } - } -} +export default ProductRepository diff --git a/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts b/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts index 4ef4cfe5bb..bd86a60631 100644 --- a/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts +++ b/packages/medusa/src/repositories/publishable-api-key-sales-channel.ts @@ -1,91 +1,94 @@ -import { Brackets, EntityRepository, In, Repository } from "typeorm" +import { Brackets, In } from "typeorm" import { PublishableApiKeySalesChannel, SalesChannel } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(PublishableApiKeySalesChannel) -export class PublishableApiKeySalesChannelRepository extends Repository { - /** - * Query a list of sales channels that are assigned to the publishable key scope - * - * @param publishableApiKeyId - id of the key to retrieve channels for - * @param config - querying params - */ - public async findSalesChannels( - publishableApiKeyId: string, - config?: { q?: string } - ): Promise { - const query = this.createQueryBuilder("PublishableKeySalesChannel") - .select("PublishableKeySalesChannel.sales_channel_id") - .innerJoinAndMapOne( - "PublishableKeySalesChannel.sales_channel_id", - SalesChannel, - "SalesChannel", - "PublishableKeySalesChannel.sales_channel_id = SalesChannel.id" - ) - .where( - "PublishableKeySalesChannel.publishable_key_id = :publishableApiKeyId", - { - publishableApiKeyId, - } +export const PublishableApiKeySalesChannelRepository = dataSource + .getRepository(PublishableApiKeySalesChannel) + .extend({ + /** + * Query a list of sales channels that are assigned to the publishable key scope + * + * @param publishableApiKeyId - id of the key to retrieve channels for + * @param config - querying params + */ + async findSalesChannels( + publishableApiKeyId: string, + config?: { q?: string } + ): Promise { + const query = this.createQueryBuilder("PublishableKeySalesChannel") + .select("PublishableKeySalesChannel.sales_channel_id") + .innerJoinAndMapOne( + "PublishableKeySalesChannel.sales_channel_id", + SalesChannel, + "SalesChannel", + "PublishableKeySalesChannel.sales_channel_id = SalesChannel.id" + ) + .where( + "PublishableKeySalesChannel.publishable_key_id = :publishableApiKeyId", + { + publishableApiKeyId, + } + ) + + if (config?.q) { + query.andWhere( + new Brackets((qb) => { + qb.where(`SalesChannel.description ILIKE :q`, { + q: `%${config.q}%`, + }).orWhere(`SalesChannel.name ILIKE :q`, { q: `%${config.q}%` }) + }) + ) + } + + const records = await query.getMany() + + return records.map( + (record) => record.sales_channel_id as unknown as SalesChannel ) + }, - if (config?.q) { - query.andWhere( - new Brackets((qb) => { - qb.where(`SalesChannel.description ILIKE :q`, { - q: `%${config.q}%`, - }).orWhere(`SalesChannel.name ILIKE :q`, { q: `%${config.q}%` }) - }) - ) - } + /** + * Assign (multiple) sales channels to the Publishable Key scope + * + * @param publishableApiKeyId - publishable key id + * @param salesChannelIds - an array of SC ids + */ + async addSalesChannels( + publishableApiKeyId: string, + salesChannelIds: string[] + ): Promise { + await this.createQueryBuilder() + .insert() + .into("publishable_api_key_sales_channel") + .values( + salesChannelIds.map((id) => ({ + sales_channel_id: id, + publishable_key_id: publishableApiKeyId, + })) + ) + .orIgnore() + .execute() + }, - const records = await query.getMany() - - return records.map( - (record) => record.sales_channel_id as unknown as SalesChannel - ) - } - - /** - * Assign (multiple) sales channels to the Publishable Key scope - * - * @param publishableApiKeyId - publishable key id - * @param salesChannelIds - an array of SC ids - */ - public async addSalesChannels( - publishableApiKeyId: string, - salesChannelIds: string[] - ): Promise { - await this.createQueryBuilder() - .insert() - .into("publishable_api_key_sales_channel") - .values( - salesChannelIds.map((id) => ({ - sales_channel_id: id, + /** + * Remove multiple sales channels from the PK scope + * + * @param publishableApiKeyId -publishable key id + * @param salesChannelIds - an array of SC ids + */ + async removeSalesChannels( + publishableApiKeyId: string, + salesChannelIds: string[] + ): Promise { + await this.createQueryBuilder() + .delete() + .from("publishable_api_key_sales_channel") + .where({ + sales_channel_id: In(salesChannelIds), publishable_key_id: publishableApiKeyId, - })) - ) - .orIgnore() - .execute() - } - - /** - * Remove multiple sales channels from the PK scope - * - * @param publishableApiKeyId -publishable key id - * @param salesChannelIds - an array of SC ids - */ - public async removeSalesChannels( - publishableApiKeyId: string, - salesChannelIds: string[] - ): Promise { - await this.createQueryBuilder() - .delete() - .from("publishable_api_key_sales_channel") - .where({ - sales_channel_id: In(salesChannelIds), - publishable_key_id: publishableApiKeyId, - }) - .execute() - } -} + }) + .execute() + }, + }) +export default PublishableApiKeySalesChannelRepository diff --git a/packages/medusa/src/repositories/publishable-api-key.ts b/packages/medusa/src/repositories/publishable-api-key.ts index a3cd1c0e3c..e4a0f37ee0 100644 --- a/packages/medusa/src/repositories/publishable-api-key.ts +++ b/packages/medusa/src/repositories/publishable-api-key.ts @@ -1,71 +1,6 @@ -import { flatten, groupBy, merge } from "lodash" -import { EntityRepository, FindManyOptions, Repository } from "typeorm" - import { PublishableApiKey } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(PublishableApiKey) -export class PublishableApiKeyRepository extends Repository { - public async findWithRelations( - relations: (keyof PublishableApiKey | string)[] = [], - idsOrOptionsWithoutRelations: - | Omit, "relations"> - | string[] = {} - ): Promise<[PublishableApiKey[], number]> { - let entities: PublishableApiKey[] = [] - let count = 0 - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.findByIds(idsOrOptionsWithoutRelations) - count = idsOrOptionsWithoutRelations.length - } else { - const [results, resultCount] = await this.findAndCount( - idsOrOptionsWithoutRelations - ) - entities = results - count = resultCount - } - const entitiesIds = entities.map(({ id }) => id) - - const groupedRelations = {} - for (const rel of relations) { - const [topLevel] = rel.split(".") - if (groupedRelations[topLevel]) { - groupedRelations[topLevel].push(rel) - } else { - groupedRelations[topLevel] = [rel] - } - } - - const entitiesIdsWithRelations = await Promise.all( - Object.entries(groupedRelations).map(async ([_, rels]) => { - return this.findByIds(entitiesIds, { - select: ["id"], - relations: rels as string[], - }) - }) - ).then(flatten) - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) - - const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id") - return [ - Object.values(entitiesAndRelationsById).map((v) => merge({}, ...v)), - count, - ] - } - - public async findOneWithRelations( - relations: Array = [], - optionsWithoutRelations: Omit< - FindManyOptions, - "relations" - > = {} - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const [result] = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - } -} +// eslint-disable-next-line max-len +export const PublishableApiKeyRepository = dataSource.getRepository(PublishableApiKey) +export default PublishableApiKeyRepository diff --git a/packages/medusa/src/repositories/refund.ts b/packages/medusa/src/repositories/refund.ts index 17c5899d9f..435af473fa 100644 --- a/packages/medusa/src/repositories/refund.ts +++ b/packages/medusa/src/repositories/refund.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Refund } from "../models/refund" +import { Refund } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Refund) -export class RefundRepository extends Repository {} +export const RefundRepository = dataSource.getRepository(Refund) +export default RefundRepository diff --git a/packages/medusa/src/repositories/region.ts b/packages/medusa/src/repositories/region.ts index c62da11480..e2fe60896d 100644 --- a/packages/medusa/src/repositories/region.ts +++ b/packages/medusa/src/repositories/region.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Region } from "../models/region" +import { Region } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Region) -export class RegionRepository extends Repository {} +export const RegionRepository = dataSource.getRepository(Region) +export default RegionRepository diff --git a/packages/medusa/src/repositories/return-item.ts b/packages/medusa/src/repositories/return-item.ts index 0b9937f649..e22558ba0b 100644 --- a/packages/medusa/src/repositories/return-item.ts +++ b/packages/medusa/src/repositories/return-item.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { ReturnItem } from "../models/return-item" +import { ReturnItem } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(ReturnItem) -export class ReturnItemRepository extends Repository {} +export const ReturnItemRepository = dataSource.getRepository(ReturnItem) +export default ReturnItemRepository diff --git a/packages/medusa/src/repositories/return-reason.ts b/packages/medusa/src/repositories/return-reason.ts index c66869fcfb..3c9db98f29 100644 --- a/packages/medusa/src/repositories/return-reason.ts +++ b/packages/medusa/src/repositories/return-reason.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { ReturnReason } from "../models/return-reason" +import { ReturnReason } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(ReturnReason) -export class ReturnReasonRepository extends Repository {} +export const ReturnReasonRepository = dataSource.getRepository(ReturnReason) +export default ReturnReasonRepository diff --git a/packages/medusa/src/repositories/return.ts b/packages/medusa/src/repositories/return.ts index 23e4aa9397..efde970670 100644 --- a/packages/medusa/src/repositories/return.ts +++ b/packages/medusa/src/repositories/return.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Return } from "../models/return" +import { Return } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Return) -export class ReturnRepository extends Repository {} +export const ReturnRepository = dataSource.getRepository(Return) +export default ReturnRepository diff --git a/packages/medusa/src/repositories/sales-channel.ts b/packages/medusa/src/repositories/sales-channel.ts index 788defe954..d7da56af0c 100644 --- a/packages/medusa/src/repositories/sales-channel.ts +++ b/packages/medusa/src/repositories/sales-channel.ts @@ -1,139 +1,72 @@ -import { - Brackets, - DeleteResult, - EntityRepository, - FindManyOptions, - In, - Repository, -} from "typeorm" +import { Brackets, DeleteResult, FindOptionsWhere, In } from "typeorm" import { SalesChannel } from "../models" -import { ExtendedFindConfig, Selector } from "../types/common" -import { flatten, groupBy, merge } from "lodash" +import { ExtendedFindConfig } from "../types/common" +import { dataSource } from "../loaders/database" -@EntityRepository(SalesChannel) -export class SalesChannelRepository extends Repository { - public async findWithRelations( - relations: (keyof SalesChannel | string)[] = [], - idsOrOptionsWithoutRelations: - | Omit, "relations"> - | string[] = {} - ): Promise<[SalesChannel[], number]> { - let entities: SalesChannel[] = [] - let count = 0 - if (Array.isArray(idsOrOptionsWithoutRelations)) { - entities = await this.findByIds(idsOrOptionsWithoutRelations) - count = idsOrOptionsWithoutRelations.length - } else { - const [results, resultCount] = await this.findAndCount( - idsOrOptionsWithoutRelations - ) - entities = results - count = resultCount - } - const entitiesIds = entities.map(({ id }) => id) - - const groupedRelations = {} - for (const rel of relations) { - const [topLevel] = rel.split(".") - if (groupedRelations[topLevel]) { - groupedRelations[topLevel].push(rel) - } else { - groupedRelations[topLevel] = [rel] +export const SalesChannelRepository = dataSource + .getRepository(SalesChannel) + .extend({ + async getFreeTextSearchResultsAndCount( + q: string, + options: ExtendedFindConfig = { + where: {}, } - } + ): Promise<[SalesChannel[], number]> { + const options_ = { ...options } + options_.where = options_.where as FindOptionsWhere - const entitiesIdsWithRelations = await Promise.all( - Object.entries(groupedRelations).map(async ([_, rels]) => { - return this.findByIds(entitiesIds, { - select: ["id"], - relations: rels as string[], - }) - }) - ).then(flatten) - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) + delete options_?.where?.name + delete options_?.where?.description - const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id") - return [ - Object.values(entitiesAndRelationsById).map((v) => merge({}, ...v)), - count, - ] - } + let qb = this.createQueryBuilder("sales_channel") + .select() + .where(options_.where) + .andWhere( + new Brackets((qb) => { + qb.where(`sales_channel.description ILIKE :q`, { + q: `%${q}%`, + }).orWhere(`sales_channel.name ILIKE :q`, { q: `%${q}%` }) + }) + ) + .skip(options.skip) + .take(options.take) - public async getFreeTextSearchResultsAndCount( - q: string, - options: ExtendedFindConfig> = { - where: {}, - } - ): Promise<[SalesChannel[], number]> { - const options_ = { ...options } - delete options_?.where?.name - delete options_?.where?.description + if (options.withDeleted) { + qb = qb.withDeleted() + } - let qb = this.createQueryBuilder("sales_channel") - .select() - .where(options_.where) - .andWhere( - new Brackets((qb) => { - qb.where(`sales_channel.description ILIKE :q`, { - q: `%${q}%`, - }).orWhere(`sales_channel.name ILIKE :q`, { q: `%${q}%` }) - }) - ) - .skip(options.skip) - .take(options.take) + return await qb.getManyAndCount() + }, - if (options.withDeleted) { - qb = qb.withDeleted() - } - - return await qb.getManyAndCount() - } - - async removeProducts( - salesChannelId: string, - productIds: string[] - ): Promise { - return await this.createQueryBuilder() - .delete() - .from("product_sales_channel") - .where({ - sales_channel_id: salesChannelId, - product_id: In(productIds), - }) - .execute() - } - - async addProducts( - salesChannelId: string, - productIds: string[] - ): Promise { - await this.createQueryBuilder() - .insert() - .into("product_sales_channel") - .values( - productIds.map((id) => ({ + async removeProducts( + salesChannelId: string, + productIds: string[] + ): Promise { + return await this.createQueryBuilder() + .delete() + .from("product_sales_channel") + .where({ sales_channel_id: salesChannelId, - product_id: id, - })) - ) - .orIgnore() - .execute() - } + product_id: In(productIds), + }) + .execute() + }, - public async findOneWithRelations( - relations: Array = [], - optionsWithoutRelations: Omit< - FindManyOptions, - "relations" - > = {} - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const [result] = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - } -} + async addProducts( + salesChannelId: string, + productIds: string[] + ): Promise { + await this.createQueryBuilder() + .insert() + .into("product_sales_channel") + .values( + productIds.map((id) => ({ + sales_channel_id: salesChannelId, + product_id: id, + })) + ) + .orIgnore() + .execute() + }, + }) +export default SalesChannelRepository diff --git a/packages/medusa/src/repositories/shipping-method-tax-line.ts b/packages/medusa/src/repositories/shipping-method-tax-line.ts index 061eb0c9cd..b7656cac59 100644 --- a/packages/medusa/src/repositories/shipping-method-tax-line.ts +++ b/packages/medusa/src/repositories/shipping-method-tax-line.ts @@ -1,41 +1,43 @@ -import { EntityRepository, Repository } from "typeorm" -import { ShippingMethodTaxLine } from "../models/shipping-method-tax-line" +import { ShippingMethodTaxLine } from "../models" import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" +import { dataSource } from "../loaders/database" -@EntityRepository(ShippingMethodTaxLine) -// eslint-disable-next-line max-len -export class ShippingMethodTaxLineRepository extends Repository { - async upsertLines( - lines: ShippingMethodTaxLine[] - ): Promise { - const insertResult = await this.createQueryBuilder() - .insert() - .values(lines as QueryDeepPartialEntity[]) - .orUpdate({ - conflict_target: ["shipping_method_id", "code"], - overwrite: ["rate", "name", "updated_at"], - }) - .execute() +export const ShippingMethodTaxLineRepository = dataSource + .getRepository(ShippingMethodTaxLine) + .extend({ + async upsertLines( + lines: ShippingMethodTaxLine[] + ): Promise { + const insertResult = await this.createQueryBuilder() + .insert() + .values(lines as QueryDeepPartialEntity[]) + .orUpdate({ + conflict_target: ["shipping_method_id", "code"], + overwrite: ["rate", "name", "updated_at"], + }) + .execute() - return insertResult.identifiers as ShippingMethodTaxLine[] - } + return insertResult.identifiers as ShippingMethodTaxLine[] + }, - async deleteForCart(cartId: string): Promise { - const qb = this.createQueryBuilder("line") - .select(["line.id"]) - .innerJoin("shipping_method", "sm", "sm.id = line.shipping_method_id") - .innerJoin( - "cart", - "c", - "sm.cart_id = :cartId AND c.completed_at is NULL", - { cartId } - ) + async deleteForCart(cartId: string): Promise { + const qb = this.createQueryBuilder("line") + .select(["line.id"]) + .innerJoin("shipping_method", "sm", "sm.id = line.shipping_method_id") + .innerJoin( + "cart", + "c", + "sm.cart_id = :cartId AND c.completed_at is NULL", + { cartId } + ) - const toDelete = await qb.getMany() + const toDelete = await qb.getMany() - await this.createQueryBuilder() - .delete() - .whereInIds(toDelete.map((d) => d.id)) - .execute() - } -} + await this.createQueryBuilder() + .delete() + .whereInIds(toDelete.map((d) => d.id)) + .execute() + }, + }) + +export default ShippingMethodTaxLineRepository diff --git a/packages/medusa/src/repositories/shipping-method.ts b/packages/medusa/src/repositories/shipping-method.ts index 347026ad9f..c06c693b17 100644 --- a/packages/medusa/src/repositories/shipping-method.ts +++ b/packages/medusa/src/repositories/shipping-method.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { ShippingMethod } from "../models/shipping-method" +import { ShippingMethod } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(ShippingMethod) -export class ShippingMethodRepository extends Repository {} +export const ShippingMethodRepository = dataSource.getRepository(ShippingMethod) +export default ShippingMethodRepository diff --git a/packages/medusa/src/repositories/shipping-option-requirement.ts b/packages/medusa/src/repositories/shipping-option-requirement.ts index 36f6f7ded8..69e2f78a37 100644 --- a/packages/medusa/src/repositories/shipping-option-requirement.ts +++ b/packages/medusa/src/repositories/shipping-option-requirement.ts @@ -1,6 +1,7 @@ -import { EntityRepository, Repository } from "typeorm" -import { ShippingOptionRequirement } from "../models/shipping-option-requirement" +import { ShippingOptionRequirement } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(ShippingOptionRequirement) -// eslint-disable-next-line max-len -export class ShippingOptionRequirementRepository extends Repository {} +export const ShippingOptionRequirementRepository = dataSource.getRepository( + ShippingOptionRequirement +) +export default ShippingOptionRequirementRepository diff --git a/packages/medusa/src/repositories/shipping-option.ts b/packages/medusa/src/repositories/shipping-option.ts index 51a0d941fb..a668d8d6f1 100644 --- a/packages/medusa/src/repositories/shipping-option.ts +++ b/packages/medusa/src/repositories/shipping-option.ts @@ -1,18 +1,22 @@ -import { EntityRepository, In, Repository } from "typeorm" -import { ShippingOption } from "../models/shipping-option" +import { ShippingOption } from "../models" +import { dataSource } from "../loaders/database" +import { In } from "typeorm" -@EntityRepository(ShippingOption) -export class ShippingOptionRepository extends Repository { - public async upsertShippingProfile( - shippingOptionIds: string[], - shippingProfileId: string - ): Promise { - await this.createQueryBuilder() - .update(ShippingOption) - .set({ profile_id: shippingProfileId }) - .where({ id: In(shippingOptionIds) }) - .execute() +export const ShippingOptionRepository = dataSource + .getRepository(ShippingOption) + .extend({ + async upsertShippingProfile( + shippingOptionIds: string[], + shippingProfileId: string + ): Promise { + await this.createQueryBuilder() + .update(ShippingOption) + .set({ profile_id: shippingProfileId }) + .where({ id: In(shippingOptionIds) }) + .execute() - return this.findByIds(shippingOptionIds) - } -} + return this.findByIds(shippingOptionIds) + }, + }) + +export default ShippingOptionRepository diff --git a/packages/medusa/src/repositories/shipping-profile.ts b/packages/medusa/src/repositories/shipping-profile.ts index d9a027f329..3b777a703d 100644 --- a/packages/medusa/src/repositories/shipping-profile.ts +++ b/packages/medusa/src/repositories/shipping-profile.ts @@ -1,5 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" -import { ShippingProfile } from "../models/shipping-profile" +import { ShippingProfile } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(ShippingProfile) -export class ShippingProfileRepository extends Repository {} +export const ShippingProfileRepository = + dataSource.getRepository(ShippingProfile) +export default ShippingProfileRepository diff --git a/packages/medusa/src/repositories/shipping-tax-rate.ts b/packages/medusa/src/repositories/shipping-tax-rate.ts index 2a68b2a451..986544672e 100644 --- a/packages/medusa/src/repositories/shipping-tax-rate.ts +++ b/packages/medusa/src/repositories/shipping-tax-rate.ts @@ -1,5 +1,6 @@ -import { EntityRepository, Repository } from "typeorm" -import { ShippingTaxRate } from "../models/shipping-tax-rate" +import { ShippingTaxRate } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(ShippingTaxRate) -export class ShippingTaxRateRepository extends Repository {} +export const ShippingTaxRateRepository = + dataSource.getRepository(ShippingTaxRate) +export default ShippingTaxRateRepository diff --git a/packages/medusa/src/repositories/staged-job.ts b/packages/medusa/src/repositories/staged-job.ts index 0323ab29a3..6b60ad297f 100644 --- a/packages/medusa/src/repositories/staged-job.ts +++ b/packages/medusa/src/repositories/staged-job.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { StagedJob } from "../models/staged-job" +import { StagedJob } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(StagedJob) -export class StagedJobRepository extends Repository {} +export const StagedJobRepository = dataSource.getRepository(StagedJob) +export default StagedJobRepository diff --git a/packages/medusa/src/repositories/store.ts b/packages/medusa/src/repositories/store.ts index c3922a1933..b3986e939f 100644 --- a/packages/medusa/src/repositories/store.ts +++ b/packages/medusa/src/repositories/store.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { Store } from "../models/store" +import { Store } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Store) -export class StoreRepository extends Repository {} +export const StoreRepository = dataSource.getRepository(Store) +export default StoreRepository diff --git a/packages/medusa/src/repositories/swap.ts b/packages/medusa/src/repositories/swap.ts index 1431d625f3..dfbfa0c01f 100644 --- a/packages/medusa/src/repositories/swap.ts +++ b/packages/medusa/src/repositories/swap.ts @@ -1,53 +1,5 @@ -import { flatten, groupBy, map, merge } from "lodash" -import { EntityRepository, FindManyOptions, Repository } from "typeorm" -import { Swap } from "../models/swap" +import { Swap } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(Swap) -export class SwapRepository extends Repository { - public async findWithRelations( - relations: Array = [], - optionsWithoutRelations: Omit, "relations"> = {} - ): Promise { - const entities = await this.find(optionsWithoutRelations) - const entitiesIds = entities.map(({ id }) => id) - - const groupedRelations = {} - for (const rel of relations) { - const [topLevel] = rel.split(".") - if (groupedRelations[topLevel]) { - groupedRelations[topLevel].push(rel) - } else { - groupedRelations[topLevel] = [rel] - } - } - - const entitiesIdsWithRelations = await Promise.all( - Object.entries(groupedRelations).map(async ([_, rels]) => { - return this.findByIds(entitiesIds, { - select: ["id"], - relations: rels as string[], - }) - }) - ).then(flatten) - - const entitiesAndRelations = entitiesIdsWithRelations.concat(entities) - - const entitiesAndRelationsById = groupBy(entitiesAndRelations, "id") - - return map(entities, (e) => merge({}, ...entitiesAndRelationsById[e.id])) - } - - public async findOneWithRelations( - relations: Array = [], - optionsWithoutRelations: Omit, "relations"> = {} - ): Promise { - // Limit 1 - optionsWithoutRelations.take = 1 - - const result = await this.findWithRelations( - relations, - optionsWithoutRelations - ) - return result[0] - } -} +export const SwapRepository = dataSource.getRepository(Swap) +export default SwapRepository diff --git a/packages/medusa/src/repositories/tax-provider.ts b/packages/medusa/src/repositories/tax-provider.ts index 24c963f429..f98804db91 100644 --- a/packages/medusa/src/repositories/tax-provider.ts +++ b/packages/medusa/src/repositories/tax-provider.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { TaxProvider } from "../models/tax-provider" +import { TaxProvider } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(TaxProvider) -export class TaxProviderRepository extends Repository {} +export const TaxProviderRepository = dataSource.getRepository(TaxProvider) +export default TaxProviderRepository diff --git a/packages/medusa/src/repositories/tax-rate.ts b/packages/medusa/src/repositories/tax-rate.ts index 5b231555f8..c5788737db 100644 --- a/packages/medusa/src/repositories/tax-rate.ts +++ b/packages/medusa/src/repositories/tax-rate.ts @@ -1,12 +1,10 @@ import { unionBy } from "lodash" import { DeleteResult, - EntityRepository, FindManyOptions, - FindOptionsUtils, + FindOptionsSelect, In, Not, - Repository, SelectQueryBuilder, } from "typeorm" import { @@ -18,6 +16,8 @@ import { } from "../models" import { TaxRateListByConfig } from "../types/tax-rate" import { isDefined } from "medusa-core-utils" +import { buildLegacyFieldsListFrom } from "../utils" +import { dataSource } from "../loaders/database" const resolveableFields = [ "product_count", @@ -25,8 +25,7 @@ const resolveableFields = [ "shipping_option_count", ] -@EntityRepository(TaxRate) -export class TaxRateRepository extends Repository { +export const TaxRateRepository = dataSource.getRepository(TaxRate).extend({ getFindQueryBuilder(findOptions: FindManyOptions) { const qb = this.createQueryBuilder("tr") const cleanOptions = findOptions @@ -34,7 +33,10 @@ export class TaxRateRepository extends Repository { const resolverFields: string[] = [] if (isDefined(findOptions.select)) { const selectableCols: (keyof TaxRate)[] = [] - for (const k of findOptions.select) { + const legacySelect = buildLegacyFieldsListFrom( + findOptions.select as FindOptionsSelect + ) + for (const k of legacySelect) { if (!resolveableFields.includes(k)) { selectableCols.push(k) } else { @@ -44,32 +46,29 @@ export class TaxRateRepository extends Repository { cleanOptions.select = selectableCols } - FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder( - qb, - cleanOptions - ) + qb.setFindOptions(cleanOptions) if (resolverFields.length > 0) { this.applyResolutionsToQueryBuilder(qb, resolverFields) } return qb - } + }, async findWithResolution(findOptions: FindManyOptions) { const qb = this.getFindQueryBuilder(findOptions) return await qb.getMany() - } + }, async findOneWithResolution(findOptions: FindManyOptions) { const qb = this.getFindQueryBuilder(findOptions) return await qb.getOne() - } + }, async findAndCountWithResolution(findOptions: FindManyOptions) { const qb = this.getFindQueryBuilder(findOptions) return await qb.getManyAndCount() - } + }, applyResolutionsToQueryBuilder( qb: SelectQueryBuilder, @@ -101,7 +100,7 @@ export class TaxRateRepository extends Repository { } return qb - } + }, async removeFromProduct( id: string, @@ -112,7 +111,7 @@ export class TaxRateRepository extends Repository { .from(ProductTaxRate) .where({ rate_id: id, product_id: In(productIds) }) .execute() - } + }, async addToProduct( id: string, @@ -140,7 +139,7 @@ export class TaxRateRepository extends Repository { .select() .where(insertResult.identifiers) .getMany() - } + }, async removeFromProductType( id: string, @@ -151,7 +150,7 @@ export class TaxRateRepository extends Repository { .from(ProductTypeTaxRate) .where({ rate_id: id, product_type_id: In(productTypeIds) }) .execute() - } + }, async addToProductType( id: string, @@ -182,7 +181,7 @@ export class TaxRateRepository extends Repository { .select() .where(insertResult.identifiers) .getMany() - } + }, async removeFromShippingOption( id: string, @@ -193,7 +192,7 @@ export class TaxRateRepository extends Repository { .from(ShippingTaxRate) .where({ rate_id: id, shipping_option_id: In(optionIds) }) .execute() - } + }, async addToShippingOption( id: string, @@ -224,7 +223,7 @@ export class TaxRateRepository extends Repository { .select() .where(insertResult.identifiers) .getMany() - } + }, async listByProduct(productId: string, config: TaxRateListByConfig) { const productRates = this.createQueryBuilder("txr") @@ -254,7 +253,7 @@ export class TaxRateRepository extends Repository { // Only return unique rates by joining the two arrays from typeRates and // productRates matching based on the id return unionBy(...results, (txr) => txr.id) - } + }, async listByShippingOption(optionId: string) { const rates = this.createQueryBuilder("txr") @@ -262,5 +261,6 @@ export class TaxRateRepository extends Repository { .where("ptr.shipping_option_id = :optionId", { optionId }) return await rates.getMany() - } -} + }, +}) +export default TaxRateRepository diff --git a/packages/medusa/src/repositories/tracking-link.ts b/packages/medusa/src/repositories/tracking-link.ts index 785321a045..6d341d4b3b 100644 --- a/packages/medusa/src/repositories/tracking-link.ts +++ b/packages/medusa/src/repositories/tracking-link.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { TrackingLink } from "../models/tracking-link" +import { TrackingLink } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(TrackingLink) -export class TrackingLinkRepository extends Repository {} +export const TrackingLinkRepository = dataSource.getRepository(TrackingLink) +export default TrackingLinkRepository diff --git a/packages/medusa/src/repositories/user.ts b/packages/medusa/src/repositories/user.ts index ead949ad13..a49b2d55eb 100644 --- a/packages/medusa/src/repositories/user.ts +++ b/packages/medusa/src/repositories/user.ts @@ -1,5 +1,5 @@ -import { EntityRepository, Repository } from "typeorm" -import { User } from "../models/user" +import { User } from "../models" +import { dataSource } from "../loaders/database" -@EntityRepository(User) -export class UserRepository extends Repository {} +export const UserRepository = dataSource.getRepository(User) +export default UserRepository diff --git a/packages/medusa/src/scripts/discount-rule-migration.ts b/packages/medusa/src/scripts/discount-rule-migration.ts index f77a0e96a2..291f095489 100644 --- a/packages/medusa/src/scripts/discount-rule-migration.ts +++ b/packages/medusa/src/scripts/discount-rule-migration.ts @@ -1,13 +1,8 @@ - import dotenv from "dotenv" -import { createConnection } from "typeorm" +import { DataSource } from "typeorm" import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity" import Logger from "../loaders/logger" -import { - DiscountCondition, - DiscountConditionOperator, - DiscountConditionType, -} from "../models/discount-condition" +import { DiscountCondition, DiscountConditionOperator, DiscountConditionType, } from "../models/discount-condition" import { DiscountConditionProduct } from "../models/discount-condition-product" import { DiscountRule } from "../models/discount-rule" import { DiscountConditionRepository } from "../repositories/discount-condition" @@ -16,11 +11,12 @@ import { typeormConfig } from "./db-config" dotenv.config() const migrate = async function ({ typeormConfig }): Promise { - const connection = await createConnection(typeormConfig) + const dataSource = new DataSource(typeormConfig) + await dataSource.initialize() const BATCH_SIZE = 1000 - await connection.transaction(async (manager) => { + await dataSource.transaction(async (manager) => { const discountRuleCount = await manager .createQueryBuilder() .from(DiscountRule, "dr") @@ -42,18 +38,22 @@ const migrate = async function ({ typeormConfig }): Promise { .offset(offset) .getRawMany() - const discountConditionRepo = manager - .getCustomRepository(DiscountConditionRepository) + const discountConditionRepo = manager.withRepository( + DiscountConditionRepository + ) await manager .createQueryBuilder() .insert() .into(DiscountCondition) .values( - discountRules.map((dr) => discountConditionRepo.create({ - type: DiscountConditionType.PRODUCTS, - operator: DiscountConditionOperator.IN, - discount_rule_id: dr.dr_id, - }) as QueryDeepPartialEntity) + discountRules.map( + (dr) => + discountConditionRepo.create({ + type: DiscountConditionType.PRODUCTS, + operator: DiscountConditionOperator.IN, + discount_rule_id: dr.dr_id, + }) as QueryDeepPartialEntity + ) ) .orIgnore() .execute() @@ -98,11 +98,13 @@ const migrate = async function ({ typeormConfig }): Promise { }) // Validate results - const noDanglingProductsValidation = await connection.manager - .query(`SELECT drp.discount_rule_id, drp.product_id, dcp.product_id FROM "discount_rule_products" drp - LEFT JOIN discount_condition dc ON dc.discount_rule_id = drp.discount_rule_id - LEFT JOIN discount_condition_product dcp ON dcp.condition_id = dc.id AND dcp.product_id = drp.product_id - WHERE dcp.product_id IS NULL`) + const noDanglingProductsValidation = await dataSource.manager + .query(`SELECT drp.discount_rule_id, drp.product_id, dcp.product_id + FROM "discount_rule_products" drp + LEFT JOIN discount_condition dc ON dc.discount_rule_id = drp.discount_rule_id + LEFT JOIN discount_condition_product dcp + ON dcp.condition_id = dc.id AND dcp.product_id = drp.product_id + WHERE dcp.product_id IS NULL`) if ( noDanglingProductsValidation && diff --git a/packages/medusa/src/services/__tests__/cart.js b/packages/medusa/src/services/__tests__/cart.js index 9bab2f7538..74c7ed0c46 100644 --- a/packages/medusa/src/services/__tests__/cart.js +++ b/packages/medusa/src/services/__tests__/cart.js @@ -65,7 +65,7 @@ describe("CartService", () => { describe("retrieve", () => { let result const cartRepository = MockRepository({ - findOneWithRelations: () => + findOne: () => Promise.resolve({ id: IdMap.getId("emptyCart") }), }) beforeAll(async () => { @@ -82,9 +82,8 @@ describe("CartService", () => { }) it("calls cart model functions", () => { - expect(cartRepository.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(cartRepository.findOneWithRelations).toHaveBeenCalledWith( - undefined, + expect(cartRepository.findOne).toHaveBeenCalledTimes(1) + expect(cartRepository.findOne).toHaveBeenCalledWith( { where: { id: IdMap.getId("emptyCart") }, select: undefined, @@ -129,7 +128,7 @@ describe("CartService", () => { ) expect(cartRepository.findOne).toBeCalledTimes(1) - expect(cartRepository.findOne).toBeCalledWith(id) + expect(cartRepository.findOne).toBeCalledWith({ where: { id } }) expect(cartRepository.save).toBeCalledTimes(1) expect(cartRepository.save).toBeCalledWith({ @@ -346,7 +345,7 @@ describe("CartService", () => { } const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { if (q.where.id === IdMap.getId("cartWithLine")) { return Promise.resolve({ id: IdMap.getId("cartWithLine"), @@ -587,7 +586,7 @@ describe("CartService", () => { } const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { if (q.where.id === IdMap.getId("cartWithLine")) { return Promise.resolve({ id: IdMap.getId("cartWithLine"), @@ -673,7 +672,7 @@ describe("CartService", () => { }, } const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { if (q.where.id === IdMap.getId("withShipping")) { return Promise.resolve({ shipping_methods: [ @@ -816,7 +815,7 @@ describe("CartService", () => { describe("update", () => { const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { if (q.where.id === "withpays") { return Promise.resolve({ payment_sessions: [ @@ -847,24 +846,31 @@ describe("CartService", () => { cartService.setPaymentSessions = jest.fn() await cartService.update("withpays", {}) - expect(cartRepository.findOneWithRelations).toHaveBeenCalledWith( - expect.arrayContaining([ - "items", - "shipping_methods", - "shipping_address", - "billing_address", - "gift_cards", - "customer", - "region", - "payment_sessions", - "region.countries", - "discounts", - "discounts.rule", - "discounts.regions", - ]), - { - where: { id: "withpays" }, - } + expect(cartRepository.findOne).toHaveBeenCalledWith( + expect.objectContaining({ + relations: { + billing_address: true, + customer: true, + discounts: { + regions: true, + rule: true + }, + gift_cards: true, + items: { + variant: { + product: true + } + }, + payment_sessions: true, + region: { countries: true }, + shipping_address: true, + shipping_methods: true + }, + select: undefined, + where: { + id: "withpays" + } + }), ) }) }) @@ -904,7 +910,7 @@ describe("CartService", () => { } const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { if (q.where.id === IdMap.getId("cannot")) { return Promise.resolve({ items: [ @@ -1016,7 +1022,7 @@ describe("CartService", () => { }, } const cartRepository = MockRepository({ - findOneWithRelations: () => Promise.resolve({}), + findOne: () => Promise.resolve({}), }) const cartService = new CartService({ manager: MockManager, @@ -1088,7 +1094,7 @@ describe("CartService", () => { describe("updateBillingAddress", () => { const cartRepository = MockRepository({ - findOneWithRelations: () => + findOne: () => Promise.resolve({ region: { countries: [{ iso_2: "us" }] }, }), @@ -1150,7 +1156,7 @@ describe("CartService", () => { describe("updateShippingAddress", () => { const cartRepository = MockRepository({ - findOneWithRelations: () => + findOne: () => Promise.resolve({ region: { countries: [{ iso_2: "us" }] }, }), @@ -1231,6 +1237,16 @@ describe("CartService", () => { const lineItemService = { update: jest.fn((r) => r), delete: jest.fn(), + retrieve: jest.fn().mockImplementation((lineItemId) => { + if (lineItemId === IdMap.getId("existing")) { + return Promise.resolve({ + id: lineItemId, + }) + } + return Promise.resolve({ + id: lineItemId, + }) + }), withTransaction: function () { return this }, @@ -1256,7 +1272,7 @@ describe("CartService", () => { }, } const cartRepository = MockRepository({ - findOneWithRelations: () => + findOne: () => Promise.resolve({ items: [ { @@ -1361,7 +1377,9 @@ describe("CartService", () => { shipping_address: { country_code: "us", }, - items: [IdMap.getId("testitem")], + items: [{ + id: IdMap.getId("testitem") + }], payment_session: null, payment_sessions: [], gift_cards: [], @@ -1378,7 +1396,7 @@ describe("CartService", () => { describe("setPaymentSession", () => { const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { if (q.where.id === IdMap.getId("cartWithLine")) { return Promise.resolve({ total: 100, @@ -1586,7 +1604,7 @@ describe("CartService", () => { } const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { if (q.where.id === IdMap.getId("cart-to-filter")) { return Promise.resolve(cart3) } @@ -1792,7 +1810,7 @@ describe("CartService", () => { const cartWithCustomSO = buildCart("cart-with-custom-so") const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { switch (q.where.id) { case IdMap.getId("lines"): return Promise.resolve(cart3) @@ -1991,7 +2009,7 @@ describe("CartService", () => { } const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { if (q.where.id === IdMap.getId("with-d")) { return Promise.resolve({ id: IdMap.getId("cart"), @@ -2480,7 +2498,7 @@ describe("CartService", () => { describe("removeDiscount", () => { const cartRepository = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { return Promise.resolve({ id: IdMap.getId("cart"), discounts: [ diff --git a/packages/medusa/src/services/__tests__/claim.js b/packages/medusa/src/services/__tests__/claim.js index 3213bf246a..a10027e86e 100644 --- a/packages/medusa/src/services/__tests__/claim.js +++ b/packages/medusa/src/services/__tests__/claim.js @@ -514,7 +514,7 @@ describe("ClaimService", () => { expect(claimRepo.findOne).toHaveBeenCalledWith({ where: { id: "claim_id" }, - relations: ["order"], + relations: { order: true }, }) }) }) diff --git a/packages/medusa/src/services/__tests__/custom-shipping-option.js b/packages/medusa/src/services/__tests__/custom-shipping-option.js index 35290b9746..b2d5df6bcc 100644 --- a/packages/medusa/src/services/__tests__/custom-shipping-option.js +++ b/packages/medusa/src/services/__tests__/custom-shipping-option.js @@ -37,7 +37,9 @@ describe("CustomShippingOptionService", () => { where: { cart_id: "test-cso-cart", }, - relations: ["shipping_option"], + relations: { + "shipping_option": true + }, }) }) }) @@ -73,7 +75,10 @@ describe("CustomShippingOptionService", () => { expect(customShippingOptionRepository.findOne).toHaveBeenCalledTimes(1) expect(customShippingOptionRepository.findOne).toHaveBeenCalledWith({ where: { id: "cso-test" }, - relations: ["shipping_option", "cart"], + relations: { + "shipping_option": true, + "cart": true, + }, }) }) diff --git a/packages/medusa/src/services/__tests__/customer.js b/packages/medusa/src/services/__tests__/customer.js index 4e01a03f9d..9bf4bbd1e7 100644 --- a/packages/medusa/src/services/__tests__/customer.js +++ b/packages/medusa/src/services/__tests__/customer.js @@ -192,7 +192,7 @@ describe("CustomerService", () => { expect(customerRepository.listAndCount).toHaveBeenCalledWith( { - relations: [], + relations: {}, skip: 0, take: 2, where: { diff --git a/packages/medusa/src/services/__tests__/gift-card.js b/packages/medusa/src/services/__tests__/gift-card.js index 1603815f86..74c28479d6 100644 --- a/packages/medusa/src/services/__tests__/gift-card.js +++ b/packages/medusa/src/services/__tests__/gift-card.js @@ -65,7 +65,7 @@ describe("GiftCardService", () => { describe("retrieve", () => { const giftCardRepo = MockRepository({ - findOneWithRelations: () => { + findOne: () => { return Promise.resolve({}) }, }) @@ -85,22 +85,19 @@ describe("GiftCardService", () => { select: ["id"], }) - expect(giftCardRepo.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(giftCardRepo.findOneWithRelations).toHaveBeenCalledWith( - ["region"], - { - where: { - id: IdMap.getId("gift-card"), - }, - select: ["id"], - } - ) + expect(giftCardRepo.findOne).toHaveBeenCalledTimes(1) + expect(giftCardRepo.findOne).toHaveBeenCalledWith({ + relationLoadStrategy: "query", + relations: { region: true }, + select: { id: true }, + where: { id: IdMap.getId("gift-card") }, + }) }) }) describe("retrieveByCode", () => { const giftCardRepo = MockRepository({ - findOneWithRelations: () => { + findOne: () => { return Promise.resolve({}) }, }) @@ -120,16 +117,13 @@ describe("GiftCardService", () => { select: ["id"], }) - expect(giftCardRepo.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(giftCardRepo.findOneWithRelations).toHaveBeenCalledWith( - ["region"], - { - where: { - code: "1234-1234-1234-1234", - }, - select: ["id"], - } - ) + expect(giftCardRepo.findOne).toHaveBeenCalledTimes(1) + expect(giftCardRepo.findOne).toHaveBeenCalledWith({ + "relationLoadStrategy": "query", + "relations": {"region": true}, + "select": {"id": true}, + "where": {"code": "1234-1234-1234-1234"} + }) }) }) @@ -142,7 +136,7 @@ describe("GiftCardService", () => { } const giftCardRepo = MockRepository({ - findOneWithRelations: (s) => { + findOne: (s) => { return Promise.resolve(giftCard) }, save: (s) => { diff --git a/packages/medusa/src/services/__tests__/invite.js b/packages/medusa/src/services/__tests__/invite.js index 404e2f6532..5f5a8cd557 100644 --- a/packages/medusa/src/services/__tests__/invite.js +++ b/packages/medusa/src/services/__tests__/invite.js @@ -14,7 +14,7 @@ describe("InviteService", () => { }) const inviteService = new InviteService({ - manager: { getCustomRepository: jest.fn(() => inviteRepo) }, + manager: { withRepository: jest.fn(() => inviteRepo) }, userService: {}, userRepository: {}, inviteRepository: inviteRepo, @@ -192,7 +192,7 @@ describe("InviteService", () => { const inviteRepo = MockRepository({ findOne: (q) => { return Promise.resolve({ - id: q.id, + id: q.where.id, role: "admin", user_email: "test@test.com", }) @@ -200,7 +200,7 @@ describe("InviteService", () => { }) const inviteService = new InviteService({ - manager: { getCustomRepository: jest.fn(() => inviteRepo) }, + manager: { withRepository: jest.fn(() => inviteRepo) }, userService: {}, userRepository: {}, inviteRepository: inviteRepo, diff --git a/packages/medusa/src/services/__tests__/line-item-adjustment.js b/packages/medusa/src/services/__tests__/line-item-adjustment.js index ade0c3a1c3..3158940d39 100644 --- a/packages/medusa/src/services/__tests__/line-item-adjustment.js +++ b/packages/medusa/src/services/__tests__/line-item-adjustment.js @@ -41,7 +41,7 @@ describe("LineItemAdjustmentService", () => { where: { item_id: "li-1", }, - relations: ["item"], + relations: { "item": true }, }) }) }) @@ -78,7 +78,7 @@ describe("LineItemAdjustmentService", () => { expect(lineItemAdjustmentRepo.findOne).toHaveBeenCalledTimes(1) expect(lineItemAdjustmentRepo.findOne).toHaveBeenCalledWith({ where: { id: "lia-1" }, - relations: ["item"], + relations: { "item": true }, }) }) diff --git a/packages/medusa/src/services/__tests__/note.js b/packages/medusa/src/services/__tests__/note.js index ee002fd9ab..39cfe5eb96 100644 --- a/packages/medusa/src/services/__tests__/note.js +++ b/packages/medusa/src/services/__tests__/note.js @@ -1,5 +1,5 @@ import NoteService from "../note" -import { MockManager, MockRepository, IdMap } from "medusa-test-utils" +import { IdMap, MockManager, MockRepository } from "medusa-test-utils" import { EventBusServiceMock } from "../__mocks__/event-bus" describe("NoteService", () => { @@ -33,7 +33,7 @@ describe("NoteService", () => { where: { resource_id: IdMap.getId("note"), }, - relations: ["author"], + relations: { author: true }, }) }) }) @@ -68,7 +68,7 @@ describe("NoteService", () => { expect(noteRepo.findOne).toHaveBeenCalledTimes(1) expect(noteRepo.findOne).toHaveBeenCalledWith({ where: { id: IdMap.getId("note") }, - relations: ["author"], + relations: { author: true }, }) }) diff --git a/packages/medusa/src/services/__tests__/order-edit-item-change.ts b/packages/medusa/src/services/__tests__/order-edit-item-change.ts index c4581210a1..7f491ed7b9 100644 --- a/packages/medusa/src/services/__tests__/order-edit-item-change.ts +++ b/packages/medusa/src/services/__tests__/order-edit-item-change.ts @@ -1,12 +1,7 @@ import { IdMap, MockManager, MockRepository } from "medusa-test-utils" -import { - EventBusService, - LineItemService, - OrderEditItemChangeService, - TaxProviderService, -} from "../index" +import { EventBusService, LineItemService, OrderEditItemChangeService, TaxProviderService, } from "../index" import { EventBusServiceMock } from "../__mocks__/event-bus" -import { FindManyOptions, In } from "typeorm" +import { In } from "typeorm" import { LineItemServiceMock } from "../__mocks__/line-item" const taxProviderServiceMock = { @@ -25,7 +20,7 @@ describe("OrderEditItemChangeService", () => { delete: jest.fn().mockImplementation(() => { return Promise.resolve() }), - find: jest.fn().mockImplementation((conditions: FindManyOptions) => { + find: jest.fn().mockImplementation((conditions) => { return Promise.resolve( conditions.where?.id?.value?.map((id) => ({ id, diff --git a/packages/medusa/src/services/__tests__/order.js b/packages/medusa/src/services/__tests__/order.js index 15b27b21d0..69785c5025 100644 --- a/packages/medusa/src/services/__tests__/order.js +++ b/packages/medusa/src/services/__tests__/order.js @@ -510,7 +510,7 @@ describe("OrderService", () => { it("calls order model functions", async () => { await orderService.retrieve(IdMap.getId("test-order")) expect(orderRepo.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(orderRepo.findOneWithRelations).toHaveBeenCalledWith(undefined, { + expect(orderRepo.findOneWithRelations).toHaveBeenCalledWith({}, { where: { id: IdMap.getId("test-order") }, }) }) diff --git a/packages/medusa/src/services/__tests__/price-list.js b/packages/medusa/src/services/__tests__/price-list.js index 3c385f024d..066e3b9d96 100644 --- a/packages/medusa/src/services/__tests__/price-list.js +++ b/packages/medusa/src/services/__tests__/price-list.js @@ -131,7 +131,7 @@ describe("PriceListService", () => { .fn() .mockImplementation(() => Promise.resolve()) updateRelatedMoneyAmountRepository.updatePriceListPrices = - new MoneyAmountRepository().updatePriceListPrices + MoneyAmountRepository.updatePriceListPrices const updateRelatedPriceListService = new PriceListService({ manager: MockManager, diff --git a/packages/medusa/src/services/__tests__/product-variant.js b/packages/medusa/src/services/__tests__/product-variant.js index 389f19bbe8..d853d3e86e 100644 --- a/packages/medusa/src/services/__tests__/product-variant.js +++ b/packages/medusa/src/services/__tests__/product-variant.js @@ -670,6 +670,9 @@ describe("ProductVariantService", () => { name: "California", }) }, + withTransaction: function () { + return this + }, } const productVariantService = new ProductVariantService({ diff --git a/packages/medusa/src/services/__tests__/product.js b/packages/medusa/src/services/__tests__/product.js index 29b5c92843..bd87e29306 100644 --- a/packages/medusa/src/services/__tests__/product.js +++ b/packages/medusa/src/services/__tests__/product.js @@ -29,7 +29,7 @@ const mockUpsertType = jest.fn().mockImplementation((value) => { describe("ProductService", () => { describe("retrieve", () => { const productRepo = MockRepository({ - findOneWithRelations: (rels, query) => { + findOne: (query) => { if (query.where.id === "test id with variants") { return { id: "test id with variants", @@ -62,8 +62,8 @@ describe("ProductService", () => { it("successfully retrieves a product", async () => { const result = await productService.retrieve(IdMap.getId("ironman")) - expect(productRepo.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(productRepo.findOneWithRelations).toHaveBeenCalledWith(undefined, { + expect(productRepo.findOne).toHaveBeenCalledTimes(1) + expect(productRepo.findOne).toHaveBeenCalledWith({ where: { id: IdMap.getId("ironman") }, }) @@ -80,7 +80,7 @@ describe("ProductService", () => { collection: { id: IdMap.getId("cat"), title: "Suits" }, variants: product.variants, }), - findOneWithRelations: () => ({ + findOne: () => ({ id: IdMap.getId("ironman"), title: "Suit", options: [], @@ -210,7 +210,7 @@ describe("ProductService", () => { describe("update", () => { const productRepository = MockRepository({ - findOneWithRelations: (rels, query) => { + findOne: (query) => { if (query.where.id === IdMap.getId("ironman&co")) { return Promise.resolve({ id: IdMap.getId("ironman&co"), @@ -414,7 +414,7 @@ describe("ProductService", () => { describe("addOption", () => { const productRepository = MockRepository({ - findOneWithRelations: (query) => + findOne: (query) => Promise.resolve({ id: IdMap.getId("ironman"), options: [{ title: "Color" }], @@ -487,7 +487,7 @@ describe("ProductService", () => { describe("reorderVariants", () => { const productRepository = MockRepository({ - findOneWithRelations: (query) => + findOne: (query) => Promise.resolve({ id: IdMap.getId("ironman"), variants: [{ id: IdMap.getId("green") }, { id: IdMap.getId("blue") }], @@ -546,7 +546,7 @@ describe("ProductService", () => { describe("updateOption", () => { const productRepository = MockRepository({ - findOneWithRelations: (query) => + findOne: (query) => Promise.resolve({ id: IdMap.getId("ironman"), options: [ @@ -622,7 +622,7 @@ describe("ProductService", () => { describe("deleteOption", () => { const productRepository = MockRepository({ - findOneWithRelations: (query) => + findOne: (query) => Promise.resolve({ id: IdMap.getId("ironman"), variants: [ diff --git a/packages/medusa/src/services/__tests__/publishable-api-key.ts b/packages/medusa/src/services/__tests__/publishable-api-key.ts index 2442f0e3e2..1cc3313451 100644 --- a/packages/medusa/src/services/__tests__/publishable-api-key.ts +++ b/packages/medusa/src/services/__tests__/publishable-api-key.ts @@ -18,7 +18,7 @@ describe("PublishableApiKeyService", () => { }) const publishableApiKeyRepository = MockRepository({ - findOneWithRelations: (data) => ({ ...pubKeyToRetrieve, ...data }), + findOne: (data) => ({ ...pubKeyToRetrieve, ...data }), create: (data) => { return { ...pubKeyToRetrieve, @@ -42,13 +42,18 @@ describe("PublishableApiKeyService", () => { IdMap.getId("order-edit-with-changes") ) expect( - publishableApiKeyRepository.findOneWithRelations + publishableApiKeyRepository.findOne ).toHaveBeenCalledTimes(1) expect( - publishableApiKeyRepository.findOneWithRelations - ).toHaveBeenCalledWith(undefined, { - where: { id: IdMap.getId("order-edit-with-changes") }, - }) + publishableApiKeyRepository.findOne + ).toHaveBeenCalledWith( + { + relationLoadStrategy: "query", + where: { + id: IdMap.getId("order-edit-with-changes") + } + } + ) }) it("should create a publishable api key and call the repository with the right arguments as well as the event bus service", async () => { diff --git a/packages/medusa/src/services/__tests__/region.ts b/packages/medusa/src/services/__tests__/region.ts index 1f6dd984a0..b456a4fc33 100644 --- a/packages/medusa/src/services/__tests__/region.ts +++ b/packages/medusa/src/services/__tests__/region.ts @@ -447,7 +447,7 @@ describe("RegionService", () => { expect(regionRepository.findOne).toHaveBeenCalledTimes(1) expect(regionRepository.findOne).toHaveBeenCalledWith({ where: { id: IdMap.getId("region") }, - relations: ["countries"], + relations: { countries: true }, }) expect(regionRepository.save).toHaveBeenCalledTimes(1) diff --git a/packages/medusa/src/services/__tests__/sales-channel.ts b/packages/medusa/src/services/__tests__/sales-channel.ts index 9593264b20..b8cda0ac2a 100644 --- a/packages/medusa/src/services/__tests__/sales-channel.ts +++ b/packages/medusa/src/services/__tests__/sales-channel.ts @@ -2,7 +2,7 @@ import { IdMap, MockManager, MockRepository } from "medusa-test-utils" import SalesChannelService from "../sales-channel" import { EventBusServiceMock } from "../__mocks__/event-bus" import { EventBusService, StoreService } from "../index" -import { FindConditions, FindManyOptions, FindOneOptions } from "typeorm" +import { FindManyOptions, FindOneOptions } from "typeorm" import { SalesChannel } from "../../models" import { store, StoreServiceMock } from "../__mocks__/store" @@ -15,38 +15,12 @@ describe("SalesChannelService", () => { const salesChannelRepositoryMock = { ...MockRepository({ - findOneWithRelations: jest - .fn() - .mockImplementation( - ( - relations: Array = [], - optionsWithoutRelations: Omit< - FindManyOptions, - "relations" - > - ): any => { - return Promise.resolve({ - id: - (optionsWithoutRelations?.where as FindConditions) - ?.id ?? IdMap.getId("sc_adjhlukiaeswhfae"), - ...salesChannelData, - }) - } - ), - findOne: jest - .fn() - .mockImplementation( - (queryOrId: string | FindOneOptions): any => { - return Promise.resolve({ - id: - typeof queryOrId === "string" - ? queryOrId - : (queryOrId?.where as FindConditions)?.id ?? - IdMap.getId("sc_adjhlukiaeswhfae"), - ...salesChannelData, - }) - } - ), + findOne: jest.fn().mockImplementation((query) => { + return Promise.resolve({ + id: query.where.id, + ...salesChannelData, + }) + }), findAndCount: jest.fn().mockImplementation(() => Promise.resolve([ { @@ -168,9 +142,10 @@ describe("SalesChannelService", () => { }) expect( - salesChannelRepositoryMock.findOneWithRelations - ).toHaveBeenLastCalledWith(undefined, { + salesChannelRepositoryMock.findOne + ).toHaveBeenLastCalledWith({ where: { id: IdMap.getId("sales_channel_1") }, + relationLoadStrategy: "query" }) }) }) diff --git a/packages/medusa/src/services/__tests__/shipping-option.js b/packages/medusa/src/services/__tests__/shipping-option.js index 12b1f56bdb..597f2bd6c0 100644 --- a/packages/medusa/src/services/__tests__/shipping-option.js +++ b/packages/medusa/src/services/__tests__/shipping-option.js @@ -342,10 +342,13 @@ describe("ShippingOptionService", () => { softRemove: (q) => { return Promise.resolve() }, - findOne: (i) => - i.where.id === IdMap.getId("requirement_id") - ? { id: IdMap.getId("requirement_id") } - : null, + findOne: (i) => { + if (i.where.id === IdMap.getId("requirement_id")) { + return { id: IdMap.getId("requirement_id") } + } else { + return null + } + } }) const optionService = new ShippingOptionService({ @@ -371,7 +374,7 @@ describe("ShippingOptionService", () => { it("is idempotent", async () => { await optionService.removeRequirement(IdMap.getId("validId"), "something") - expect(shippingOptionRequirementRepository.softRemove).toBeCalledTimes(1) + expect(shippingOptionRequirementRepository.softRemove).toBeCalledTimes(0) }) }) diff --git a/packages/medusa/src/services/__tests__/swap.ts b/packages/medusa/src/services/__tests__/swap.ts index cd10da6139..769b2aefe7 100644 --- a/packages/medusa/src/services/__tests__/swap.ts +++ b/packages/medusa/src/services/__tests__/swap.ts @@ -26,7 +26,7 @@ import LineItemAdjustmentService from "../line-item-adjustment" /* ******************** DEFAULT REPOSITORY MOCKS ******************** */ const swapRepo = MockRepository({ - findOneWithRelations: (existing) => Promise.resolve(existing), + findOne: (existing) => Promise.resolve(existing), create: jest.fn().mockImplementation((data) => { return Object.assign(new Swap(), data) }), @@ -230,7 +230,7 @@ describe("SwapService", () => { } as unknown as CartService const swapRepo = MockRepository({ - findOneWithRelations: () => Promise.resolve(existing), + findOne: () => Promise.resolve(existing), }) const customShippingOptionService = { @@ -269,28 +269,37 @@ describe("SwapService", () => { { option_id: "test-option", price: 10 }, ]) - expect(swapRepo.findOneWithRelations).toHaveBeenCalledTimes(1) - expect(swapRepo.findOneWithRelations).toHaveBeenCalledWith( - [ - "order", - "order.items", - "order.swaps", - "order.swaps.additional_items", - "order.discounts", - "order.discounts.rule", - "order.claims", - "order.claims.additional_items", - "additional_items", - "additional_items.variant", - "return_order", - "return_order.items", - "return_order.shipping_method", - "return_order.shipping_method.tax_lines", - ], - { - where: { id: IdMap.getId("swap-1") }, - } - ) + expect(swapRepo.findOne).toHaveBeenCalledTimes(1) + expect(swapRepo.findOne).toHaveBeenCalledWith({ + relations: { + additional_items: { + variant: true + }, + order: { + claims: { + additional_items: true + }, + discounts: { + rule: true + }, + items: { + variant: { + product: true + } + }, + swaps: { + additional_items: true + } + }, + return_order: { + items: true, + shipping_method: { + tax_lines: true + } + } + }, + where: { id: IdMap.getId("swap-1") } + }) expect(lineItemService.createReturnLines).toHaveBeenCalledTimes(1) expect(lineItemService.createReturnLines).toHaveBeenCalledWith( @@ -358,7 +367,7 @@ describe("SwapService", () => { } const swapRepo = MockRepository({ - findOneWithRelations: (_, query) => { + findOne: (query) => { switch (query.where.id) { case IdMap.getId("canceled"): return Promise.resolve({ @@ -554,7 +563,7 @@ describe("SwapService", () => { } as unknown as LineItemService const swapRepo = MockRepository({ - findOneWithRelations: () => Promise.resolve({ ...existing }), + findOne: () => Promise.resolve({ ...existing }), }) const swapService = new SwapService({ ...defaultProps, @@ -596,14 +605,14 @@ describe("SwapService", () => { shipping_methods: existing.shipping_methods, }, [{ item_id: "1234", quantity: 2 }], - { swap_id: IdMap.getId("swap"), metadata: {} } + { swap_id: IdMap.getId("swap"), metadata: {} }, ) }) }) describe("failure", () => { const swapRepo = MockRepository({ - findOneWithRelations: () => + findOne: () => Promise.resolve({ canceled_at: new Date(), }), @@ -625,7 +634,7 @@ describe("SwapService", () => { describe("cancelFulfillment", () => { const swapRepo = MockRepository({ - findOneWithRelations: () => Promise.resolve({}), + findOne: () => Promise.resolve({}), save: (f) => Promise.resolve(f), }) @@ -746,7 +755,7 @@ describe("SwapService", () => { } as unknown as CartService const swapRepo = MockRepository({ - findOneWithRelations: () => Promise.resolve(existing), + findOne: () => Promise.resolve(existing), }) const swapService = new SwapService({ @@ -789,7 +798,7 @@ describe("SwapService", () => { describe("failure", () => { const swapRepo = MockRepository({ - findOneWithRelations: () => + findOne: () => Promise.resolve({ canceled_at: new Date() }), }) @@ -892,7 +901,7 @@ describe("SwapService", () => { cart) as unknown as CartService["retrieveWithTotals"] const swapRepo = MockRepository({ - findOneWithRelations: () => Promise.resolve(existing), + findOne: () => Promise.resolve(existing), }) const swapService = new SwapService({ @@ -944,7 +953,7 @@ describe("SwapService", () => { } const swapRepo = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { switch (q.where.id) { case IdMap.getId("canceled"): return Promise.resolve({ canceled_at: new Date() }) @@ -1011,7 +1020,7 @@ describe("SwapService", () => { }) const swapRepo = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { switch (q.where.id) { case "refund": return Promise.resolve(existing(-1, false)) @@ -1133,7 +1142,7 @@ describe("SwapService", () => { }) const swapRepo = MockRepository({ - findOneWithRelations: (rels, q) => { + findOne: (q) => { switch (q.where.id) { case "requested": return Promise.resolve({ @@ -1190,7 +1199,7 @@ describe("SwapService", () => { const fulfillment = { canceled_at: now } const swapRepo = MockRepository({ - findOneWithRelations: (_, q) => { + findOne: (q) => { const swap: any = { payment: { ...payment }, return_order: { ...return_order }, diff --git a/packages/medusa/src/services/analytics-config.ts b/packages/medusa/src/services/analytics-config.ts index 149310c8a7..3784c8f60e 100644 --- a/packages/medusa/src/services/analytics-config.ts +++ b/packages/medusa/src/services/analytics-config.ts @@ -32,7 +32,7 @@ class AnalyticsConfigService extends TransactionBaseService { async retrieve(userId: string): Promise { const manager = this.manager_ - const analyticsRepo = manager.getCustomRepository( + const analyticsRepo = manager.withRepository( this.analyticsConfigRepository_ ) @@ -58,7 +58,7 @@ class AnalyticsConfigService extends TransactionBaseService { data: CreateAnalyticsConfig ): Promise { const manager = this.transactionManager_ || this.manager_ - const analyticsRepo = manager.getCustomRepository( + const analyticsRepo = manager.withRepository( this.analyticsConfigRepository_ ) @@ -75,7 +75,7 @@ class AnalyticsConfigService extends TransactionBaseService { ): Promise { const manager = this.transactionManager_ || this.manager_ - const analyticsRepo = manager.getCustomRepository( + const analyticsRepo = manager.withRepository( this.analyticsConfigRepository_ ) @@ -102,7 +102,7 @@ class AnalyticsConfigService extends TransactionBaseService { */ async delete(userId: string): Promise { const manager = this.transactionManager_ || this.manager_ - const analyticsRepo = manager.getCustomRepository( + const analyticsRepo = manager.withRepository( this.analyticsConfigRepository_ ) diff --git a/packages/medusa/src/services/batch-job.ts b/packages/medusa/src/services/batch-job.ts index e331e21f69..ada355b786 100644 --- a/packages/medusa/src/services/batch-job.ts +++ b/packages/medusa/src/services/batch-job.ts @@ -117,7 +117,7 @@ class BatchJobService extends TransactionBaseService { } const manager = this.manager_ - const batchJobRepo = manager.getCustomRepository(this.batchJobRepository_) + const batchJobRepo = manager.withRepository(this.batchJobRepository_) const query = buildQuery({ id: batchJobId }, config) const batchJob = await batchJobRepo.findOne(query) @@ -137,7 +137,7 @@ class BatchJobService extends TransactionBaseService { config: FindConfig = { skip: 0, take: 20 } ): Promise<[BatchJob[], number]> { const manager = this.manager_ - const batchJobRepo = manager.getCustomRepository(this.batchJobRepository_) + const batchJobRepo = manager.withRepository(this.batchJobRepository_) const query = buildQuery(selector, config) return await batchJobRepo.findAndCount(query) @@ -145,9 +145,7 @@ class BatchJobService extends TransactionBaseService { async create(data: BatchJobCreateProps): Promise { return await this.atomicPhase_(async (manager) => { - const batchJobRepo: BatchJobRepository = manager.getCustomRepository( - this.batchJobRepository_ - ) + const batchJobRepo = manager.withRepository(this.batchJobRepository_) const batchJob = batchJobRepo.create(data) const result = await batchJobRepo.save(batchJob) @@ -167,9 +165,7 @@ class BatchJobService extends TransactionBaseService { data: BatchJobUpdateProps ): Promise { return await this.atomicPhase_(async (manager) => { - const batchJobRepo: BatchJobRepository = manager.getCustomRepository( - this.batchJobRepository_ - ) + const batchJobRepo = manager.withRepository(this.batchJobRepository_) let batchJob = batchJobOrId as BatchJob if (typeof batchJobOrId === "string") { @@ -225,7 +221,7 @@ class BatchJobService extends TransactionBaseService { batchJob[entityColumnName] = new Date() - const batchJobRepo = transactionManager.getCustomRepository( + const batchJobRepo = transactionManager.withRepository( this.batchJobRepository_ ) batchJob = await batchJobRepo.save(batchJob) diff --git a/packages/medusa/src/services/cart.ts b/packages/medusa/src/services/cart.ts index 9c0dda7648..a2deffc4a5 100644 --- a/packages/medusa/src/services/cart.ts +++ b/packages/medusa/src/services/cart.ts @@ -203,7 +203,7 @@ class CartService extends TransactionBaseService { config: FindConfig = {} ): Promise { const manager = this.manager_ - const cartRepo = manager.getCustomRepository(this.cartRepository_) + const cartRepo = manager.withRepository(this.cartRepository_) const query = buildQuery(selector, config) return await cartRepo.find(query) @@ -235,18 +235,14 @@ class CartService extends TransactionBaseService { } const manager = this.manager_ - const cartRepo = manager.getCustomRepository(this.cartRepository_) - + const cartRepo = manager.withRepository(this.cartRepository_) const query = buildQuery({ id: cartId }, options) if ((options.select || []).length === 0) { query.select = undefined } - const queryRelations = query.relations - query.relations = undefined - - const raw = await cartRepo.findOneWithRelations(queryRelations, query) + const raw = await cartRepo.findOne(query) if (!raw) { throw new MedusaError( @@ -271,22 +267,19 @@ class CartService extends TransactionBaseService { totalsConfig: TotalsConfig = {} ): Promise { const manager = this.manager_ - const cartRepo = manager.getCustomRepository(this.cartRepository_) + const cartRepo = manager.withRepository(this.cartRepository_) const { select, relations, totalsToSelect } = this.transformQueryForTotals_(options) - const query = buildQuery({ id: cartId }, { ...options, select, relations }) + const query = buildQuery({ id: cartId }, { + ...options, + select, + relations, + } as FindConfig) - if (relations && relations.length > 0) { - query.relations = relations - } + const raw = await cartRepo.findOne(query) - query.select = select?.length ? select : undefined - - const queryRelations = query.relations - query.relations = undefined - const raw = await cartRepo.findOneWithRelations(queryRelations, query) if (!raw) { throw new MedusaError( MedusaError.Types.NOT_FOUND, @@ -320,10 +313,8 @@ class CartService extends TransactionBaseService { async create(data: CartCreateProps): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const cartRepo = transactionManager.getCustomRepository( - this.cartRepository_ - ) - const addressRepo = transactionManager.getCustomRepository( + const cartRepo = transactionManager.withRepository(this.cartRepository_) + const addressRepo = transactionManager.withRepository( this.addressRepository_ ) @@ -392,7 +383,9 @@ class CartService extends TransactionBaseService { rawCart.shipping_address = data.shipping_address } if (data.shipping_address_id) { - const addr = await addressRepo.findOne(data.shipping_address_id) + const addr = await addressRepo.findOne({ + where: { id: data.shipping_address_id }, + }) if ( addr?.country_code && !regCountries.includes(addr.country_code) @@ -416,7 +409,9 @@ class CartService extends TransactionBaseService { rawCart.billing_address = data.billing_address } if (data.billing_address_id) { - const addr = await addressRepo.findOne(data.billing_address_id) + const addr = await addressRepo.findOne({ + where: { id: data.billing_address_id }, + }) if (addr?.country_code && !regCountries.includes(addr.country_code)) { throw new MedusaError( MedusaError.Types.NOT_ALLOWED, @@ -509,7 +504,7 @@ class CartService extends TransactionBaseService { .deleteShippingMethods(cart.shipping_methods) } - const lineItemRepository = transactionManager.getCustomRepository( + const lineItemRepository = transactionManager.withRepository( this.lineItemRepository_ ) await lineItemRepository.update( @@ -526,7 +521,14 @@ class CartService extends TransactionBaseService { .delete(lineItem.id) const result = await this.retrieve(cartId, { - relations: ["items", "discounts", "discounts.rule", "region"], + relations: [ + "items", + "items.variant", + "items.variant.product", + "discounts", + "discounts.rule", + "region" + ], }) await this.refreshAdjustments_(result) @@ -720,7 +722,7 @@ class CartService extends TransactionBaseService { }) cart = await this.retrieve(cart.id, { - relations: ["items", "discounts", "discounts.rule", "region"], + relations: ["items", "items.variant", "items.variant.product", "discounts", "discounts.rule", "region"], }) await this.refreshAdjustments_(cart) @@ -893,7 +895,14 @@ class CartService extends TransactionBaseService { }) cart = await this.retrieve(cart.id, { - relations: ["items", "discounts", "discounts.rule", "region"], + relations: [ + "items", + "items.variant", + "items.variant.product", + "discounts", + "discounts.rule", + "region" + ], }) await this.refreshAdjustments_(cart) @@ -965,7 +974,14 @@ class CartService extends TransactionBaseService { .update(lineItemId, lineItemUpdate) const updatedCart = await this.retrieve(cartId, { - relations: ["items", "discounts", "discounts.rule", "region"], + relations: [ + "items", + "items.variant", + "items.variant.product", + "discounts", + "discounts.rule", + "region" + ], }) await this.refreshAdjustments_(updatedCart) @@ -996,7 +1012,7 @@ class CartService extends TransactionBaseService { const transactionManager = this.transactionManager_ ?? this.manager_ if (cart.shipping_methods?.length) { - const shippingMethodRepository = transactionManager.getCustomRepository( + const shippingMethodRepository = transactionManager.withRepository( this.shippingMethodRepository_ ) @@ -1035,11 +1051,11 @@ class CartService extends TransactionBaseService { async update(cartId: string, data: CartUpdateProps): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const cartRepo = transactionManager.getCustomRepository( - this.cartRepository_ - ) + const cartRepo = transactionManager.withRepository(this.cartRepository_) const relations = [ "items", + "items.variant", + "items.variant.product", "shipping_methods", "shipping_address", "billing_address", @@ -1092,7 +1108,7 @@ class CartService extends TransactionBaseService { await this.setRegion_(cart, data.region_id, countryCode) } - const addrRepo = transactionManager.getCustomRepository( + const addrRepo = transactionManager.withRepository( this.addressRepository_ ) @@ -1292,7 +1308,7 @@ class CartService extends TransactionBaseService { protected async updateBillingAddress_( cart: Cart, addressOrId: AddressPayload | Partial
| string, - addrRepo: AddressRepository + addrRepo: typeof AddressRepository ): Promise { let address: Address if (typeof addressOrId === `string`) { @@ -1330,7 +1346,7 @@ class CartService extends TransactionBaseService { protected async updateShippingAddress_( cart: Cart, addressOrId: AddressPayload | Partial
| string, - addrRepo: AddressRepository + addrRepo: typeof AddressRepository ): Promise { let address: Address @@ -1505,6 +1521,8 @@ class CartService extends TransactionBaseService { const cart = await this.retrieve(cartId, { relations: [ "items", + "items.variant", + "items.variant.product", "region", "discounts", "discounts.rule", @@ -1525,9 +1543,7 @@ class CartService extends TransactionBaseService { (discount) => discount.code !== discountCode ) - const cartRepo = transactionManager.getCustomRepository( - this.cartRepository_ - ) + const cartRepo = transactionManager.withRepository(this.cartRepository_) const updatedCart = await cartRepo.save(cart) await this.refreshAdjustments_(updatedCart) @@ -1597,12 +1613,12 @@ class CartService extends TransactionBaseService { ): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const cartRepository = transactionManager.getCustomRepository( + const cartRepository = transactionManager.withRepository( this.cartRepository_ ) const cart = await this.retrieveWithTotals(cartId, { - relations: ["payment_sessions"], + relations: ["payment_sessions", "items", "items.variant", "items.variant.product"], }) // If cart total is 0, we don't perform anything payment related @@ -1666,12 +1682,15 @@ class CartService extends TransactionBaseService { async setPaymentSession(cartId: string, providerId: string): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const psRepo = transactionManager.getCustomRepository( + const psRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) const cart = await this.retrieveWithTotals(cartId, { relations: [ + "items", + "items.variant", + "items.variant.product", "customer", "region", "region.payment_providers", @@ -1698,7 +1717,7 @@ class CartService extends TransactionBaseService { currentlySelectedSession && currentlySelectedSession.provider_id !== providerId ) { - const psRepo = transactionManager.getCustomRepository( + const psRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) @@ -1781,7 +1800,7 @@ class CartService extends TransactionBaseService { async setPaymentSessions(cartOrCartId: Cart | string): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const psRepo = transactionManager.getCustomRepository( + const psRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) @@ -1796,6 +1815,8 @@ class CartService extends TransactionBaseService { { relations: [ "items", + "items.variant", + "items.variant.product", "items.adjustments", "discounts", "discounts.rule", @@ -1966,9 +1987,7 @@ class CartService extends TransactionBaseService { relations: ["payment_sessions"], }) - const cartRepo = transactionManager.getCustomRepository( - this.cartRepository_ - ) + const cartRepo = transactionManager.withRepository(this.cartRepository_) if (cart.payment_sessions) { const paymentSession = cart.payment_sessions.find( @@ -1979,7 +1998,7 @@ class CartService extends TransactionBaseService { ({ provider_id }) => provider_id !== providerId ) - const psRepo = transactionManager.getCustomRepository( + const psRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) @@ -1989,7 +2008,7 @@ class CartService extends TransactionBaseService { .withTransaction(transactionManager) .deleteSession(paymentSession) } else { - await psRepo.delete(paymentSession) + await psRepo.delete({ id: paymentSession.id }) } } } @@ -2037,7 +2056,7 @@ class CartService extends TransactionBaseService { provider_id: providerId, }) } else { - const psRepo = transactionManager.getCustomRepository( + const psRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) await psRepo.update(paymentSession.id, { @@ -2079,6 +2098,7 @@ class CartService extends TransactionBaseService { "items", "items.variant", "items.variant.product", + "payment_sessions", ], }) @@ -2230,10 +2250,14 @@ class CartService extends TransactionBaseService { availablePrice !== undefined && availablePrice.calculatedPrice !== null ) { - return await lineItemServiceTx.update(item.id, { + await lineItemServiceTx.update(item.id, { has_shipping: false, unit_price: availablePrice.calculatedPrice, }) + + return await lineItemServiceTx.retrieve(item.id, { + relations: ["variant", "variant.product"], + }) } return await lineItemServiceTx.delete(item.id) @@ -2274,9 +2298,7 @@ class CartService extends TransactionBaseService { cart.region = region cart.region_id = region.id - const addrRepo = transactionManager.getCustomRepository( - this.addressRepository_ - ) + const addrRepo = transactionManager.withRepository(this.addressRepository_) /* * When changing the region you are changing the set of countries that your * cart can be shipped to so we need to make sure that the current shipping @@ -2368,7 +2390,7 @@ class CartService extends TransactionBaseService { cart.gift_cards = [] if (cart.payment_sessions && cart.payment_sessions.length) { - const paymentSessionRepo = transactionManager.getCustomRepository( + const paymentSessionRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) await paymentSessionRepo.delete({ @@ -2392,6 +2414,8 @@ class CartService extends TransactionBaseService { const cart = await this.retrieve(cartId, { relations: [ "items", + "items.variant", + "items.variant.product", "discounts", "discounts.rule", "payment_sessions", @@ -2412,9 +2436,7 @@ class CartService extends TransactionBaseService { ) } - const cartRepo = transactionManager.getCustomRepository( - this.cartRepository_ - ) + const cartRepo = transactionManager.withRepository(this.cartRepository_) return cartRepo.remove(cart) } ) @@ -2436,9 +2458,7 @@ class CartService extends TransactionBaseService { ): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const cartRepo = transactionManager.getCustomRepository( - this.cartRepository_ - ) + const cartRepo = transactionManager.withRepository(this.cartRepository_) if (typeof key !== "string") { throw new MedusaError( @@ -2447,7 +2467,7 @@ class CartService extends TransactionBaseService { ) } - const cart = await cartRepo.findOne(cartId) + const cart = await cartRepo.findOne({ where: { id: cartId } }) if (!cart) { throw new MedusaError( MedusaError.Types.NOT_FOUND, @@ -2483,6 +2503,8 @@ class CartService extends TransactionBaseService { "discounts.rule", "gift_cards", "items", + "items.variant", + "items.variant.product", "items.adjustments", "region", "region.tax_rates", @@ -2749,6 +2771,8 @@ class CartService extends TransactionBaseService { const relationSet = new Set(config.relations) relationSet.add("items") + relationSet.add("items.variant") + relationSet.add("items.variant.product") relationSet.add("items.tax_lines") relationSet.add("items.adjustments") relationSet.add("gift_cards") diff --git a/packages/medusa/src/services/claim-item.ts b/packages/medusa/src/services/claim-item.ts index 0b02ac5ed1..c9ec3c98e7 100644 --- a/packages/medusa/src/services/claim-item.ts +++ b/packages/medusa/src/services/claim-item.ts @@ -48,9 +48,7 @@ class ClaimItemService extends TransactionBaseService { async create(data: CreateClaimItemInput): Promise { return await this.atomicPhase_(async (manager) => { - const ciRepo: ClaimItemRepository = manager.getCustomRepository( - this.claimItemRepository_ - ) + const ciRepo = manager.withRepository(this.claimItemRepository_) const { item_id, reason, quantity, tags, images, ...rest } = data @@ -86,9 +84,7 @@ class ClaimItemService extends TransactionBaseService { let tagsToAdd: ClaimTag[] = [] if (tags && tags.length) { - const claimTagRepo = manager.getCustomRepository( - this.claimTagRepository_ - ) + const claimTagRepo = manager.withRepository(this.claimTagRepository_) tagsToAdd = await Promise.all( tags.map(async (t) => { const normalized = t.trim().toLowerCase() @@ -105,9 +101,7 @@ class ClaimItemService extends TransactionBaseService { let imagesToAdd: ClaimImage[] = [] if (images && images.length) { - const claimImgRepo = manager.getCustomRepository( - this.claimImageRepository_ - ) + const claimImgRepo = manager.withRepository(this.claimImageRepository_) imagesToAdd = images.map((url) => { return claimImgRepo.create({ url }) }) @@ -138,7 +132,7 @@ class ClaimItemService extends TransactionBaseService { async update(id, data): Promise { return this.atomicPhase_(async (manager) => { - const ciRepo = manager.getCustomRepository(this.claimItemRepository_) + const ciRepo = manager.withRepository(this.claimItemRepository_) const item = await this.retrieve(id, { relations: ["images", "tags"] }) const { tags, images, reason, note, metadata } = data @@ -157,9 +151,7 @@ class ClaimItemService extends TransactionBaseService { if (tags) { item.tags = [] - const claimTagRepo = manager.getCustomRepository( - this.claimTagRepository_ - ) + const claimTagRepo = manager.withRepository(this.claimTagRepository_) for (const t of tags) { if (t.id) { item.tags.push(t) @@ -180,9 +172,7 @@ class ClaimItemService extends TransactionBaseService { } if (images) { - const claimImgRepo = manager.getCustomRepository( - this.claimImageRepository_ - ) + const claimImgRepo = manager.withRepository(this.claimImageRepository_) const ids = images.map((i) => i.id) for (const i of item.images) { if (!ids.includes(i.id)) { @@ -226,7 +216,7 @@ class ClaimItemService extends TransactionBaseService { order: { created_at: "DESC" }, } ): Promise { - const ciRepo = this.manager_.getCustomRepository(this.claimItemRepository_) + const ciRepo = this.manager_.withRepository(this.claimItemRepository_) const query = buildQuery(selector, config) return ciRepo.find(query) } @@ -248,7 +238,7 @@ class ClaimItemService extends TransactionBaseService { ) } - const claimItemRepo = this.manager_.getCustomRepository( + const claimItemRepo = this.manager_.withRepository( this.claimItemRepository_ ) const query = buildQuery({ id: claimItemId }, config) diff --git a/packages/medusa/src/services/claim.ts b/packages/medusa/src/services/claim.ts index ed02d2fb62..d847e6b8f2 100644 --- a/packages/medusa/src/services/claim.ts +++ b/packages/medusa/src/services/claim.ts @@ -131,7 +131,7 @@ export default class ClaimService extends TransactionBaseService { async update(id: string, data: UpdateClaimInput): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const claimRepo = transactionManager.getCustomRepository( + const claimRepo = transactionManager.withRepository( this.claimRepository_ ) const claim = await this.retrieve(id, { @@ -337,7 +337,7 @@ export default class ClaimService extends TransactionBaseService { async create(data: CreateClaimInput): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const claimRepo = transactionManager.getCustomRepository( + const claimRepo = transactionManager.withRepository( this.claimRepository_ ) @@ -359,7 +359,7 @@ export default class ClaimService extends TransactionBaseService { let addressId = shipping_address_id || order.shipping_address_id if (shipping_address) { - const addressRepo = transactionManager.getCustomRepository( + const addressRepo = transactionManager.withRepository( this.addressRepository_ ) const created = addressRepo.create(shipping_address) @@ -430,9 +430,15 @@ export default class ClaimService extends TransactionBaseService { const calcContext = await this.totalsService_.getCalculationContext( order ) - const lineItems = await lineItemServiceTx.list({ - id: result.additional_items.map((i) => i.id), - }) + const lineItems = await lineItemServiceTx.list( + { + id: result.additional_items.map((i) => i.id), + }, + { + relations: ["variant", "variant.product"], + } + ) + await this.taxProviderService_ .withTransaction(transactionManager) .createTaxLines(lineItems, calcContext) @@ -633,7 +639,7 @@ export default class ClaimService extends TransactionBaseService { } } - const claimRepo = transactionManager.getCustomRepository( + const claimRepo = transactionManager.withRepository( this.claimRepository_ ) const claimOrder = await claimRepo.save(claim) @@ -671,7 +677,7 @@ export default class ClaimService extends TransactionBaseService { claim.fulfillment_status = ClaimFulfillmentStatus.CANCELED - const claimRepo = transactionManager.getCustomRepository( + const claimRepo = transactionManager.withRepository( this.claimRepository_ ) return claimRepo.save(claim) @@ -708,7 +714,7 @@ export default class ClaimService extends TransactionBaseService { claim.payment_status = ClaimPaymentStatus.REFUNDED - const claimRepo = transactionManager.getCustomRepository( + const claimRepo = transactionManager.withRepository( this.claimRepository_ ) const claimOrder = await claimRepo.save(claim) @@ -787,7 +793,7 @@ export default class ClaimService extends TransactionBaseService { } } - const claimRepo = transactionManager.getCustomRepository( + const claimRepo = transactionManager.withRepository( this.claimRepository_ ) const claimOrder = await claimRepo.save(claim) @@ -839,7 +845,7 @@ export default class ClaimService extends TransactionBaseService { claim.fulfillment_status = ClaimFulfillmentStatus.CANCELED claim.canceled_at = new Date() - const claimRepo = transactionManager.getCustomRepository( + const claimRepo = transactionManager.withRepository( this.claimRepository_ ) const claimOrder = await claimRepo.save(claim) @@ -870,7 +876,7 @@ export default class ClaimService extends TransactionBaseService { } ): Promise { const manager = this.manager_ - const claimRepo = manager.getCustomRepository(this.claimRepository_) + const claimRepo = manager.withRepository(this.claimRepository_) const query = buildQuery(selector, config) return await claimRepo.find(query) } @@ -893,7 +899,7 @@ export default class ClaimService extends TransactionBaseService { } const manager = this.manager_ - const claimRepo = manager.getCustomRepository(this.claimRepository_) + const claimRepo = manager.withRepository(this.claimRepository_) const query = buildQuery({ id: claimId }, config) const claim = await claimRepo.findOne(query) diff --git a/packages/medusa/src/services/csv-parser.ts b/packages/medusa/src/services/csv-parser.ts index bfc184e388..f299b2359a 100644 --- a/packages/medusa/src/services/csv-parser.ts +++ b/packages/medusa/src/services/csv-parser.ts @@ -11,7 +11,7 @@ const DEFAULT_PARSE_OPTIONS = { class CsvParser< TSchema extends CsvSchema = CsvSchema, - TParserResult = unknown, + TParserResult extends object = Record, TOutputResult = unknown > extends AbstractParser { protected readonly $$delimiter: string = ";" diff --git a/packages/medusa/src/services/currency.ts b/packages/medusa/src/services/currency.ts index 7a72474091..afa16b9b19 100644 --- a/packages/medusa/src/services/currency.ts +++ b/packages/medusa/src/services/currency.ts @@ -48,7 +48,7 @@ export default class CurrencyService extends TransactionBaseService { * @return The currency */ async retrieveByCode(code: string): Promise { - const currencyRepo = this.manager_.getCustomRepository( + const currencyRepo = this.manager_.withRepository( this.currencyRepository_ ) @@ -85,7 +85,7 @@ export default class CurrencyService extends TransactionBaseService { take: 20, } ): Promise<[Currency[], number]> { - const productRepo = this.manager_.getCustomRepository( + const productRepo = this.manager_.withRepository( this.currencyRepository_ ) @@ -117,7 +117,7 @@ export default class CurrencyService extends TransactionBaseService { } } - const currencyRepo = transactionManager.getCustomRepository( + const currencyRepo = transactionManager.withRepository( this.currencyRepository_ ) await currencyRepo.save(currency) diff --git a/packages/medusa/src/services/custom-shipping-option.ts b/packages/medusa/src/services/custom-shipping-option.ts index 84dd2efeb8..75d97bfbcb 100644 --- a/packages/medusa/src/services/custom-shipping-option.ts +++ b/packages/medusa/src/services/custom-shipping-option.ts @@ -39,7 +39,7 @@ class CustomShippingOptionService extends TransactionBaseService { config: FindConfig = {} ): Promise { const manager = this.manager_ - const customShippingOptionRepo = manager.getCustomRepository( + const customShippingOptionRepo = manager.withRepository( this.customShippingOptionRepository_ ) @@ -71,7 +71,7 @@ class CustomShippingOptionService extends TransactionBaseService { } ): Promise { const manager = this.manager_ - const customShippingOptionRepo = manager.getCustomRepository( + const customShippingOptionRepo = manager.withRepository( this.customShippingOptionRepository_ ) @@ -92,7 +92,7 @@ class CustomShippingOptionService extends TransactionBaseService { const { cart_id, shipping_option_id, price, metadata } = data const manager = this.manager_ - const customShippingOptionRepo = manager.getCustomRepository( + const customShippingOptionRepo = manager.withRepository( this.customShippingOptionRepository_ ) diff --git a/packages/medusa/src/services/customer-group.ts b/packages/medusa/src/services/customer-group.ts index 4d52dd9b4d..b293861e6f 100644 --- a/packages/medusa/src/services/customer-group.ts +++ b/packages/medusa/src/services/customer-group.ts @@ -1,5 +1,5 @@ import { isDefined, MedusaError } from "medusa-core-utils" -import { DeepPartial, EntityManager, ILike } from "typeorm" +import { DeepPartial, EntityManager, FindOptionsWhere, ILike } from "typeorm" import { CustomerService } from "." import { CustomerGroup } from ".." import { @@ -45,9 +45,7 @@ class CustomerGroupService extends TransactionBaseService { ) } - const cgRepo = this.manager_.getCustomRepository( - this.customerGroupRepository_ - ) + const cgRepo = this.manager_.withRepository(this.customerGroupRepository_) const query = buildQuery({ id: customerGroupId }, config) @@ -70,7 +68,7 @@ class CustomerGroupService extends TransactionBaseService { async create(group: DeepPartial): Promise { return await this.atomicPhase_(async (manager) => { try { - const cgRepo: CustomerGroupRepository = manager.getCustomRepository( + const cgRepo: typeof CustomerGroupRepository = manager.withRepository( this.customerGroupRepository_ ) @@ -104,7 +102,7 @@ class CustomerGroupService extends TransactionBaseService { return await this.atomicPhase_( async (manager) => { - const cgRepo: CustomerGroupRepository = manager.getCustomRepository( + const cgRepo: typeof CustomerGroupRepository = manager.withRepository( this.customerGroupRepository_ ) return await cgRepo.addCustomers(id, ids) @@ -129,7 +127,7 @@ class CustomerGroupService extends TransactionBaseService { return await this.atomicPhase_(async (manager) => { const { metadata, ...properties } = update - const cgRepo: CustomerGroupRepository = manager.getCustomRepository( + const cgRepo: typeof CustomerGroupRepository = manager.withRepository( this.customerGroupRepository_ ) @@ -157,7 +155,7 @@ class CustomerGroupService extends TransactionBaseService { */ async delete(groupId: string): Promise { return await this.atomicPhase_(async (manager) => { - const cgRepo: CustomerGroupRepository = manager.getCustomRepository( + const cgRepo: typeof CustomerGroupRepository = manager.withRepository( this.customerGroupRepository_ ) @@ -203,7 +201,7 @@ class CustomerGroupService extends TransactionBaseService { } = {}, config: FindConfig ): Promise<[CustomerGroup[], number]> { - const cgRepo: CustomerGroupRepository = this.manager_.getCustomRepository( + const cgRepo: typeof CustomerGroupRepository = this.manager_.withRepository( this.customerGroupRepository_ ) @@ -213,7 +211,8 @@ class CustomerGroupService extends TransactionBaseService { delete selector.q } - const query = buildQuery(selector, config) + const query = buildQuery, any>(selector, config) + query.where = query.where as FindOptionsWhere if (q) { query.where.name = ILike(`%${q}%`) @@ -241,7 +240,7 @@ class CustomerGroupService extends TransactionBaseService { id: string, customerIds: string[] | string ): Promise { - const cgRepo: CustomerGroupRepository = this.manager_.getCustomRepository( + const cgRepo: typeof CustomerGroupRepository = this.manager_.withRepository( this.customerGroupRepository_ ) let ids: string[] diff --git a/packages/medusa/src/services/customer.ts b/packages/medusa/src/services/customer.ts index 784b22b760..b60f579d87 100644 --- a/packages/medusa/src/services/customer.ts +++ b/packages/medusa/src/services/customer.ts @@ -1,14 +1,24 @@ import jwt from "jsonwebtoken" import { isDefined, MedusaError } from "medusa-core-utils" import Scrypt from "scrypt-kdf" -import { DeepPartial, EntityManager } from "typeorm" +import { + DeepPartial, + EntityManager, + FindOperator, + FindOptionsWhere, +} from "typeorm" import { EventBusService } from "." import { StorePostCustomersCustomerAddressesAddressReq } from "../api" import { TransactionBaseService } from "../interfaces" import { Address, Customer, CustomerGroup } from "../models" import { AddressRepository } from "../repositories/address" import { CustomerRepository } from "../repositories/customer" -import { AddressCreatePayload, FindConfig, Selector } from "../types/common" +import { + AddressCreatePayload, + ExtendedFindConfig, + FindConfig, + Selector, +} from "../types/common" import { CreateCustomerInput, UpdateCustomerInput } from "../types/customers" import { buildQuery, setMetadata } from "../utils" @@ -105,11 +115,11 @@ class CustomerService extends TransactionBaseService { * @return {Promise} the result of the find operation */ async list( - selector: Selector & { q?: string } = {}, + selector: Selector & { q?: string; groups?: string[] } = {}, config: FindConfig = { relations: [], skip: 0, take: 50 } ): Promise { const manager = this.manager_ - const customerRepo = manager.getCustomRepository(this.customerRepository_) + const customerRepo = manager.withRepository(this.customerRepository_) let q if ("q" in selector) { @@ -117,7 +127,14 @@ class CustomerService extends TransactionBaseService { delete selector.q } - const query = buildQuery, Customer>(selector, config) + const query = buildQuery, Customer>( + selector, + config + ) as ExtendedFindConfig & { + where: FindOptionsWhere< + Customer | (Customer & { groups?: FindOperator }) + > + } const [customers] = await customerRepo.listAndCount(query, q) return customers @@ -129,7 +146,7 @@ class CustomerService extends TransactionBaseService { * @return {Promise} the result of the find operation */ async listAndCount( - selector: Selector & { q?: string }, + selector: Selector & { q?: string; groups?: string[] }, config: FindConfig = { relations: [], skip: 0, @@ -138,7 +155,7 @@ class CustomerService extends TransactionBaseService { } ): Promise<[Customer[], number]> { const manager = this.manager_ - const customerRepo = manager.getCustomRepository(this.customerRepository_) + const customerRepo = manager.withRepository(this.customerRepository_) let q if ("q" in selector) { @@ -146,7 +163,14 @@ class CustomerService extends TransactionBaseService { delete selector.q } - const query = buildQuery, Customer>(selector, config) + const query = buildQuery( + selector, + config + ) as ExtendedFindConfig & { + where: FindOptionsWhere< + Customer | (Customer & { groups?: FindOperator }) + > + } return await customerRepo.listAndCount(query, q) } @@ -157,7 +181,7 @@ class CustomerService extends TransactionBaseService { */ async count(): Promise { const manager = this.manager_ - const customerRepo = manager.getCustomRepository(this.customerRepository_) + const customerRepo = manager.withRepository(this.customerRepository_) return await customerRepo.count({}) } @@ -167,7 +191,7 @@ class CustomerService extends TransactionBaseService { ): Promise { const manager = this.transactionManager_ ?? this.manager_ - const customerRepo = manager.getCustomRepository(this.customerRepository_) + const customerRepo = manager.withRepository(this.customerRepository_) const query = buildQuery(selector, config) const customer = await customerRepo.findOne(query) @@ -284,7 +308,7 @@ class CustomerService extends TransactionBaseService { */ async create(customer: CreateCustomerInput): Promise { return await this.atomicPhase_(async (manager) => { - const customerRepository = manager.getCustomRepository( + const customerRepository = manager.withRepository( this.customerRepository_ ) @@ -343,7 +367,7 @@ class CustomerService extends TransactionBaseService { update: UpdateCustomerInput ): Promise { return await this.atomicPhase_(async (manager) => { - const customerRepository = manager.getCustomRepository( + const customerRepository = manager.withRepository( this.customerRepository_ ) @@ -403,7 +427,7 @@ class CustomerService extends TransactionBaseService { addressOrId: string | DeepPartial
| undefined ): Promise { return await this.atomicPhase_(async (manager) => { - const addrRepo: AddressRepository = manager.getCustomRepository( + const addrRepo: typeof AddressRepository = manager.withRepository( this.addressRepository_ ) @@ -456,7 +480,7 @@ class CustomerService extends TransactionBaseService { address: StorePostCustomersCustomerAddressesAddressReq ): Promise
{ return await this.atomicPhase_(async (manager) => { - const addressRepo = manager.getCustomRepository(this.addressRepository_) + const addressRepo = manager.withRepository(this.addressRepository_) address.country_code = address.country_code?.toLowerCase() @@ -480,7 +504,7 @@ class CustomerService extends TransactionBaseService { async removeAddress(customerId: string, addressId: string): Promise { return await this.atomicPhase_(async (manager) => { - const addressRepo = manager.getCustomRepository(this.addressRepository_) + const addressRepo = manager.withRepository(this.addressRepository_) // Should not fail, if user does not exist, since delete is idempotent const address = await addressRepo.findOne({ @@ -500,9 +524,7 @@ class CustomerService extends TransactionBaseService { address: AddressCreatePayload ): Promise { return await this.atomicPhase_(async (manager) => { - const addressRepository = manager.getCustomRepository( - this.addressRepository_ - ) + const addressRepository = manager.withRepository(this.addressRepository_) address.country_code = address.country_code.toLowerCase() @@ -545,7 +567,7 @@ class CustomerService extends TransactionBaseService { */ async delete(customerId: string): Promise { return await this.atomicPhase_(async (manager) => { - const customerRepo = manager.getCustomRepository(this.customerRepository_) + const customerRepo = manager.withRepository(this.customerRepository_) // Should not fail, if user does not exist, since delete is idempotent const customer = await customerRepo.findOne({ where: { id: customerId } }) diff --git a/packages/medusa/src/services/discount-condition.ts b/packages/medusa/src/services/discount-condition.ts index 1932883209..ccf2ea546c 100644 --- a/packages/medusa/src/services/discount-condition.ts +++ b/packages/medusa/src/services/discount-condition.ts @@ -58,7 +58,7 @@ class DiscountConditionService extends TransactionBaseService { } const manager = this.manager_ - const conditionRepo = manager.getCustomRepository( + const conditionRepo = manager.withRepository( this.discountConditionRepository_ ) @@ -139,8 +139,9 @@ class DiscountConditionService extends TransactionBaseService { ) } - const discountConditionRepo: DiscountConditionRepository = - manager.getCustomRepository(this.discountConditionRepository_) + const discountConditionRepo = manager.withRepository( + this.discountConditionRepository_ + ) if (data.id) { const resolvedCondition = await this.retrieve(data.id) @@ -199,8 +200,9 @@ class DiscountConditionService extends TransactionBaseService { ) } - const discountConditionRepo: DiscountConditionRepository = - manager.getCustomRepository(this.discountConditionRepository_) + const discountConditionRepo = manager.withRepository( + this.discountConditionRepository_ + ) const resolvedCondition = await this.retrieve(data.id) @@ -219,7 +221,7 @@ class DiscountConditionService extends TransactionBaseService { async delete(discountConditionId: string): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const conditionRepo = manager.getCustomRepository( + const conditionRepo = manager.withRepository( this.discountConditionRepository_ ) diff --git a/packages/medusa/src/services/discount.ts b/packages/medusa/src/services/discount.ts index c4b55f53eb..529784b9b2 100644 --- a/packages/medusa/src/services/discount.ts +++ b/packages/medusa/src/services/discount.ts @@ -2,12 +2,11 @@ import { parse, toSeconds } from "iso8601-duration" import { isEmpty, omit } from "lodash" import { isDefined, MedusaError } from "medusa-core-utils" import { - Brackets, DeepPartial, EntityManager, + FindOptionsWhere, ILike, In, - SelectQueryBuilder, } from "typeorm" import { EventBusService, @@ -127,7 +126,7 @@ class DiscountService extends TransactionBaseService { config: FindConfig = { relations: [], skip: 0, take: 10 } ): Promise { const manager = this.manager_ - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) const query = buildQuery(selector as Selector, config) return await discountRepo.find(query) @@ -147,7 +146,7 @@ class DiscountService extends TransactionBaseService { } ): Promise<[Discount[], number]> { const manager = this.manager_ - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) let q if ("q" in selector) { @@ -158,19 +157,8 @@ class DiscountService extends TransactionBaseService { const query = buildQuery(selector as Selector, config) if (q) { - const where = query.where - - delete where.code - - query.where = (qb: SelectQueryBuilder): void => { - qb.where(where) - - qb.andWhere( - new Brackets((qb) => { - qb.where({ code: ILike(`%${q}%`) }) - }) - ) - } + query.where = query.where as FindOptionsWhere + query.where.code = ILike(`%${q}%`) } const [discounts, count] = await discountRepo.findAndCount(query) @@ -186,8 +174,8 @@ class DiscountService extends TransactionBaseService { */ async create(discount: CreateDiscountInput): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const discountRepo = manager.getCustomRepository(this.discountRepository_) - const ruleRepo = manager.getCustomRepository(this.discountRuleRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) + const ruleRepo = manager.withRepository(this.discountRuleRepository_) const conditions = discount.rule?.conditions @@ -262,7 +250,7 @@ class DiscountService extends TransactionBaseService { } const manager = this.manager_ - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) const query = buildQuery({ id: discountId }, config) const discount = await discountRepo.findOne(query) @@ -288,7 +276,7 @@ class DiscountService extends TransactionBaseService { config: FindConfig = {} ): Promise { const manager = this.manager_ - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) const normalizedCode = discountCode.toUpperCase().trim() @@ -316,7 +304,7 @@ class DiscountService extends TransactionBaseService { config: FindConfig = {} ): Promise { const manager = this.manager_ - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) const normalizedCodes = discountCodes.map((code) => code.toUpperCase().trim() @@ -346,12 +334,8 @@ class DiscountService extends TransactionBaseService { update: UpdateDiscountInput ): Promise { return await this.atomicPhase_(async (manager) => { - const discountRepo: DiscountRepository = manager.getCustomRepository( - this.discountRepository_ - ) - const ruleRepo: DiscountRuleRepository = manager.getCustomRepository( - this.discountRuleRepository_ - ) + const discountRepo = manager.withRepository(this.discountRepository_) + const ruleRepo = manager.withRepository(this.discountRuleRepository_) const discount = await this.retrieve(discountId, { relations: ["rule"], @@ -443,7 +427,7 @@ class DiscountService extends TransactionBaseService { data: CreateDynamicDiscountInput ): Promise { return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) const discount = await this.retrieve(discountId) @@ -491,7 +475,7 @@ class DiscountService extends TransactionBaseService { */ async deleteDynamicCode(discountId: string, code: string): Promise { return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) const discount = await discountRepo.findOne({ where: { parent_discount_id: discountId, code }, }) @@ -512,7 +496,7 @@ class DiscountService extends TransactionBaseService { */ async addRegion(discountId: string, regionId: string): Promise { return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) const discount = await this.retrieve(discountId, { relations: ["regions", "rule"], @@ -547,7 +531,7 @@ class DiscountService extends TransactionBaseService { */ async removeRegion(discountId: string, regionId: string): Promise { return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) const discount = await this.retrieve(discountId, { relations: ["regions"], @@ -572,7 +556,7 @@ class DiscountService extends TransactionBaseService { */ async delete(discountId: string): Promise { return await this.atomicPhase_(async (manager) => { - const discountRepo = manager.getCustomRepository(this.discountRepository_) + const discountRepo = manager.withRepository(this.discountRepository_) const discount = await discountRepo.findOne({ where: { id: discountId } }) @@ -589,8 +573,9 @@ class DiscountService extends TransactionBaseService { productId: string | undefined ): Promise { return await this.atomicPhase_(async (manager) => { - const discountConditionRepo: DiscountConditionRepository = - manager.getCustomRepository(this.discountConditionRepository_) + const discountConditionRepo = manager.withRepository( + this.discountConditionRepository_ + ) // In case of custom line items, we don't have a product id. // Instead of throwing, we simply invalidate the discount. @@ -795,8 +780,9 @@ class DiscountService extends TransactionBaseService { customerId: string | undefined ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const discountConditionRepo: DiscountConditionRepository = - manager.getCustomRepository(this.discountConditionRepository_) + const discountConditionRepo = manager.withRepository( + this.discountConditionRepository_ + ) // Instead of throwing on missing customer id, we simply invalidate the discount if (!customerId) { diff --git a/packages/medusa/src/services/draft-order.ts b/packages/medusa/src/services/draft-order.ts index b91ff2a2bc..530d554197 100644 --- a/packages/medusa/src/services/draft-order.ts +++ b/packages/medusa/src/services/draft-order.ts @@ -1,11 +1,19 @@ import { isDefined, MedusaError } from "medusa-core-utils" -import { Brackets, EntityManager, FindManyOptions, UpdateResult } from "typeorm" +import { + EntityManager, + FindOptionsWhere, + ILike, + IsNull, + Not, + Raw, + UpdateResult, +} from "typeorm" import { TransactionBaseService } from "../interfaces" import { CartType, DraftOrder, DraftOrderStatus } from "../models" import { DraftOrderRepository } from "../repositories/draft-order" import { OrderRepository } from "../repositories/order" import { PaymentRepository } from "../repositories/payment" -import { ExtendedFindConfig, FindConfig } from "../types/common" +import { FindConfig } from "../types/common" import { DraftOrderCreateProps } from "../types/draft-orders" import { buildQuery } from "../utils" import CartService from "./cart" @@ -96,9 +104,7 @@ class DraftOrderService extends TransactionBaseService { } const manager = this.manager_ - const draftOrderRepo = manager.getCustomRepository( - this.draftOrderRepository_ - ) + const draftOrderRepo = manager.withRepository(this.draftOrderRepository_) const query = buildQuery({ id: draftOrderId }, config) const draftOrder = await draftOrderRepo.findOne(query) @@ -123,9 +129,7 @@ class DraftOrderService extends TransactionBaseService { config: FindConfig = {} ): Promise { const manager = this.manager_ - const draftOrderRepo = manager.getCustomRepository( - this.draftOrderRepository_ - ) + const draftOrderRepo = manager.withRepository(this.draftOrderRepository_) const query = buildQuery({ cart_id: cartId }, config) const draftOrder = await draftOrderRepo.findOne(query) @@ -147,7 +151,7 @@ class DraftOrderService extends TransactionBaseService { async delete(draftOrderId: string): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const draftOrderRepo = transactionManager.getCustomRepository( + const draftOrderRepo = transactionManager.withRepository( this.draftOrderRepository_ ) const draftOrder = await draftOrderRepo.findOne({ @@ -177,40 +181,45 @@ class DraftOrderService extends TransactionBaseService { } ): Promise<[DraftOrder[], number]> { const manager = this.manager_ - const draftOrderRepository = manager.getCustomRepository( + const draftOrderRepository = manager.withRepository( this.draftOrderRepository_ ) const { q, ...restSelector } = selector - const query = buildQuery( - restSelector, - config - ) as FindManyOptions & ExtendedFindConfig + const query = buildQuery(restSelector, config) if (q) { - const where = query.where - delete where?.display_id + query.where = query.where as FindOptionsWhere + delete query.where?.display_id - query.join = { - alias: "draft_order", - innerJoin: { - cart: "draft_order.cart", + query.relations = query.relations ?? {} + query.relations.cart = query.relations.cart ?? true + + const innerJoinLikeConstraint = { + cart: { + id: Not(IsNull()), }, } - query.where = (qb): void => { - qb.where(where) - - qb.andWhere( - new Brackets((qb) => { - qb.where(`cart.email ILIKE :q`, { - q: `%${q}%`, - }).orWhere(`draft_order.display_id::TEXT ILIKE :displayId`, { - displayId: `${q}`, - }) - }) - ) - } + query.where = query.where as FindOptionsWhere[] + query.where = [ + { + ...query.where, + ...innerJoinLikeConstraint, + cart: { + ...innerJoinLikeConstraint.cart, + id: Not(IsNull()), + email: ILike(`%${q}%`), + }, + }, + { + ...query.where, + ...innerJoinLikeConstraint, + display_id: Raw((alias) => `CAST(${alias} as varchar) ILike :q`, { + q: `%${q}%`, + }), + }, + ] } return await draftOrderRepository.findAndCount(query) @@ -231,9 +240,7 @@ class DraftOrderService extends TransactionBaseService { } ): Promise { const manager = this.manager_ - const draftOrderRepo = manager.getCustomRepository( - this.draftOrderRepository_ - ) + const draftOrderRepo = manager.withRepository(this.draftOrderRepository_) const query = buildQuery(selector, config) @@ -248,7 +255,7 @@ class DraftOrderService extends TransactionBaseService { async create(data: DraftOrderCreateProps): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const draftOrderRepo = transactionManager.getCustomRepository( + const draftOrderRepo = transactionManager.withRepository( this.draftOrderRepository_ ) @@ -368,7 +375,7 @@ class DraftOrderService extends TransactionBaseService { ): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const draftOrderRepo = transactionManager.getCustomRepository( + const draftOrderRepo = transactionManager.withRepository( this.draftOrderRepository_ ) return await draftOrderRepo.update( @@ -397,7 +404,7 @@ class DraftOrderService extends TransactionBaseService { ): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const draftOrderRepo = transactionManager.getCustomRepository( + const draftOrderRepo = transactionManager.withRepository( this.draftOrderRepository_ ) const draftOrder = await this.retrieve(id) diff --git a/packages/medusa/src/services/event-bus.ts b/packages/medusa/src/services/event-bus.ts index f7894a2f70..457d150a54 100644 --- a/packages/medusa/src/services/event-bus.ts +++ b/packages/medusa/src/services/event-bus.ts @@ -249,7 +249,7 @@ export default class EventBusService { * as part of the rollback. */ if (this.transactionManager_) { - const stagedJobRepository = this.transactionManager_.getCustomRepository( + const stagedJobRepository = this.transactionManager_.withRepository( this.stagedJobRepository_ ) @@ -285,7 +285,7 @@ export default class EventBusService { take: 1000, } - const stagedJobRepo = this.manager_.getCustomRepository( + const stagedJobRepo = this.manager_.withRepository( this.stagedJobRepository_ ) const jobs = await stagedJobRepo.find(listConfig) diff --git a/packages/medusa/src/services/fulfillment-provider.ts b/packages/medusa/src/services/fulfillment-provider.ts index 10d426aec6..4d456f630d 100644 --- a/packages/medusa/src/services/fulfillment-provider.ts +++ b/packages/medusa/src/services/fulfillment-provider.ts @@ -56,7 +56,7 @@ class FulfillmentProviderService extends TransactionBaseService { async registerInstalledProviders(providers: string[]): Promise { return await this.atomicPhase_(async (manager) => { - const fulfillmentProviderRepo = manager.getCustomRepository( + const fulfillmentProviderRepo = manager.withRepository( this.fulfillmentProviderRepository_ ) await fulfillmentProviderRepo.update({}, { is_installed: false }) @@ -69,7 +69,7 @@ class FulfillmentProviderService extends TransactionBaseService { } async list(): Promise { - const fpRepo = this.manager_.getCustomRepository( + const fpRepo = this.manager_.withRepository( this.fulfillmentProviderRepository_ ) diff --git a/packages/medusa/src/services/fulfillment.ts b/packages/medusa/src/services/fulfillment.ts index bfdc6d794f..65b94930c4 100644 --- a/packages/medusa/src/services/fulfillment.ts +++ b/packages/medusa/src/services/fulfillment.ts @@ -142,7 +142,7 @@ class FulfillmentService extends TransactionBaseService { quantity: number ): LineItem | null { const manager = this.transactionManager_ ?? this.manager_ - const lineItemRepo = manager.getCustomRepository(this.lineItemRepository_) + const lineItemRepo = manager.withRepository(this.lineItemRepository_) if (!item) { // This will in most cases be called by a webhook so to ensure that @@ -181,7 +181,7 @@ class FulfillmentService extends TransactionBaseService { } const manager = this.manager_ - const fulfillmentRepository = manager.getCustomRepository( + const fulfillmentRepository = manager.withRepository( this.fulfillmentRepository_ ) @@ -216,7 +216,7 @@ class FulfillmentService extends TransactionBaseService { ): Promise { const { locationId } = context return await this.atomicPhase_(async (manager) => { - const fulfillmentRepository = manager.getCustomRepository( + const fulfillmentRepository = manager.withRepository( this.fulfillmentRepository_ ) @@ -302,7 +302,7 @@ class FulfillmentService extends TransactionBaseService { }) ) - const fulfillmentRepo = manager.getCustomRepository( + const fulfillmentRepo = manager.withRepository( this.fulfillmentRepository_ ) const canceled = await fulfillmentRepo.save(fulfillment) @@ -329,10 +329,10 @@ class FulfillmentService extends TransactionBaseService { const { metadata, no_notification } = config return await this.atomicPhase_(async (manager) => { - const fulfillmentRepository = manager.getCustomRepository( + const fulfillmentRepository = manager.withRepository( this.fulfillmentRepository_ ) - const trackingLinkRepo = manager.getCustomRepository( + const trackingLinkRepo = manager.withRepository( this.trackingLinkRepository_ ) diff --git a/packages/medusa/src/services/gift-card.ts b/packages/medusa/src/services/gift-card.ts index ed2edf70fe..17508eb747 100644 --- a/packages/medusa/src/services/gift-card.ts +++ b/packages/medusa/src/services/gift-card.ts @@ -6,12 +6,7 @@ import { TransactionBaseService } from "../interfaces" import { GiftCard, Region } from "../models" import { GiftCardRepository } from "../repositories/gift-card" import { GiftCardTransactionRepository } from "../repositories/gift-card-transaction" -import { - ExtendedFindConfig, - FindConfig, - QuerySelector, - Selector, -} from "../types/common" +import { FindConfig, QuerySelector, Selector } from "../types/common" import { CreateGiftCardInput, CreateGiftCardTransactionInput, @@ -87,7 +82,7 @@ class GiftCardService extends TransactionBaseService { config: FindConfig = { relations: [], skip: 0, take: 10 } ): Promise<[GiftCard[], number]> { const manager = this.manager_ - const giftCardRepo = manager.getCustomRepository(this.giftCardRepository_) + const giftCardRepo = manager.withRepository(this.giftCardRepository_) let q: string | undefined if (isDefined(selector.q)) { @@ -95,15 +90,9 @@ class GiftCardService extends TransactionBaseService { delete selector.q } - const query: ExtendedFindConfig< - GiftCard, - QuerySelector - > = buildQuery, GiftCard>(selector, config) + const query = buildQuery(selector, config) - const rels = query.relations - delete query.relations - - return await giftCardRepo.listGiftCardsAndCount(query, rels, q) + return await giftCardRepo.listGiftCardsAndCount(query, q) } /** @@ -115,31 +104,15 @@ class GiftCardService extends TransactionBaseService { selector: QuerySelector = {}, config: FindConfig = { relations: [], skip: 0, take: 10 } ): Promise { - const manager = this.manager_ - const giftCardRepo = manager.getCustomRepository(this.giftCardRepository_) - - let q: string | undefined - if (isDefined(selector.q)) { - q = selector.q - delete selector.q - } - - const query: ExtendedFindConfig< - GiftCard, - QuerySelector - > = buildQuery, GiftCard>(selector, config) - - const rels = query.relations - delete query.relations - - return await giftCardRepo.listGiftCards(query, rels, q) + const [cards] = await this.listAndCount(selector, config) + return cards } async createTransaction( data: CreateGiftCardTransactionInput ): Promise { const manager = this.manager_ - const gctRepo = manager.getCustomRepository(this.giftCardTransactionRepo_) + const gctRepo = manager.withRepository(this.giftCardTransactionRepo_) const created = gctRepo.create(data) const saved = await gctRepo.save(created) return saved.id @@ -152,7 +125,7 @@ class GiftCardService extends TransactionBaseService { */ async create(giftCard: CreateGiftCardInput): Promise { return await this.atomicPhase_(async (manager) => { - const giftCardRepo = manager.getCustomRepository(this.giftCardRepository_) + const giftCardRepo = manager.withRepository(this.giftCardRepository_) // Will throw if region does not exist const region = await this.regionService_ @@ -160,7 +133,10 @@ class GiftCardService extends TransactionBaseService { .retrieve(giftCard.region_id) const code = GiftCardService.generateCode() - const taxRate = GiftCardService.resolveTaxRate(giftCard.tax_rate || null, region) + const taxRate = GiftCardService.resolveTaxRate( + giftCard.tax_rate || null, + region + ) const toCreate = { code, ...giftCard, @@ -181,7 +157,7 @@ class GiftCardService extends TransactionBaseService { }) } - /** + /** * The tax_rate of the giftcard can depend on whether regions tax gift cards, an input * provided by the user or the tax rate. Based on these conditions, tax_rate changes. * @return the tax rate for the gift card @@ -192,7 +168,9 @@ class GiftCardService extends TransactionBaseService { ): number | null { // A gift card is always associated with a region. If the region doesn't tax gift cards, // return null - if (!region.gift_cards_taxable) return null + if (!region.gift_cards_taxable) { + return null + } // If a tax rate has been provided as an input from an external input, use that // This would handle cases where gift cards are created as a part of an order where taxes better defined @@ -210,18 +188,16 @@ class GiftCardService extends TransactionBaseService { config: FindConfig = {} ): Promise { const manager = this.manager_ - const giftCardRepo = manager.getCustomRepository(this.giftCardRepository_) + const giftCardRepo = manager.withRepository(this.giftCardRepository_) - const { relations, ...query } = buildQuery(selector, config) + const query = buildQuery(selector, config) + query.relationLoadStrategy = "query" - const giftCard = await giftCardRepo.findOneWithRelations( - relations as (keyof GiftCard)[], - query - ) + const giftCard = await giftCardRepo.findOne(query) if (!giftCard) { const selectorConstraints = Object.entries(selector) - .map((key, value) => `${key}: ${value}`) + .map(([key, value]) => `${key}: ${value}`) .join(", ") throw new MedusaError( @@ -278,7 +254,7 @@ class GiftCardService extends TransactionBaseService { update: UpdateGiftCardInput ): Promise { return await this.atomicPhase_(async (manager) => { - const giftCardRepo = manager.getCustomRepository(this.giftCardRepository_) + const giftCardRepo = manager.withRepository(this.giftCardRepository_) const giftCard = await this.retrieve(giftCardId) @@ -321,7 +297,7 @@ class GiftCardService extends TransactionBaseService { */ async delete(giftCardId: string): Promise { const manager = this.manager_ - const giftCardRepo = manager.getCustomRepository(this.giftCardRepository_) + const giftCardRepo = manager.withRepository(this.giftCardRepository_) const giftCard = await giftCardRepo.findOne({ where: { id: giftCardId } }) diff --git a/packages/medusa/src/services/idempotency-key.ts b/packages/medusa/src/services/idempotency-key.ts index d13cca507b..1c2a369604 100644 --- a/packages/medusa/src/services/idempotency-key.ts +++ b/packages/medusa/src/services/idempotency-key.ts @@ -66,7 +66,7 @@ class IdempotencyKeyService extends TransactionBaseService { */ async create(payload: CreateIdempotencyKeyInput): Promise { return await this.atomicPhase_(async (manager) => { - const idempotencyKeyRepo = manager.getCustomRepository( + const idempotencyKeyRepo = manager.withRepository( this.idempotencyKeyRepository_ ) @@ -90,7 +90,7 @@ class IdempotencyKeyService extends TransactionBaseService { ) } - const idempotencyKeyRepo = this.manager_.getCustomRepository( + const idempotencyKeyRepo = this.manager_.withRepository( this.idempotencyKeyRepository_ ) @@ -115,7 +115,7 @@ class IdempotencyKeyService extends TransactionBaseService { */ async lock(idempotencyKey: string): Promise { return await this.atomicPhase_(async (manager) => { - const idempotencyKeyRepo = manager.getCustomRepository( + const idempotencyKeyRepo = manager.withRepository( this.idempotencyKeyRepository_ ) @@ -147,7 +147,7 @@ class IdempotencyKeyService extends TransactionBaseService { update: DeepPartial ): Promise { return await this.atomicPhase_(async (manager) => { - const idempotencyKeyRepo = manager.getCustomRepository( + const idempotencyKeyRepo = manager.withRepository( this.idempotencyKeyRepository_ ) diff --git a/packages/medusa/src/services/invite.ts b/packages/medusa/src/services/invite.ts index 19d347d1af..f963ea7e04 100644 --- a/packages/medusa/src/services/invite.ts +++ b/packages/medusa/src/services/invite.ts @@ -80,7 +80,7 @@ class InviteService extends TransactionBaseService { } async list(selector, config = {}): Promise { - const inviteRepo = this.manager_.getCustomRepository(InviteRepository) + const inviteRepo = this.manager_.withRepository(InviteRepository) const query = buildQuery(selector, config) @@ -101,9 +101,9 @@ class InviteService extends TransactionBaseService { ): Promise { return await this.atomicPhase_(async (manager) => { const inviteRepository = - this.manager_.getCustomRepository(InviteRepository) + this.manager_.withRepository(InviteRepository) - const userRepo = this.manager_.getCustomRepository(UserRepository) + const userRepo = this.manager_.withRepository(UserRepository) const userEntity = await userRepo.findOne({ where: { email: user }, @@ -167,8 +167,8 @@ class InviteService extends TransactionBaseService { */ async delete(inviteId): Promise { return await this.atomicPhase_(async (manager) => { - const inviteRepo: InviteRepository = - manager.getCustomRepository(InviteRepository) + const inviteRepo: typeof InviteRepository = + manager.withRepository(InviteRepository) // Should not fail, if invite does not exist, since delete is idempotent const invite = await inviteRepo.findOne({ where: { id: inviteId } }) @@ -195,8 +195,8 @@ class InviteService extends TransactionBaseService { const { invite_id, user_email } = decoded return await this.atomicPhase_(async (m) => { - const userRepo = m.getCustomRepository(this.userRepo_) - const inviteRepo: InviteRepository = m.getCustomRepository( + const userRepo = m.withRepository(this.userRepo_) + const inviteRepo: typeof InviteRepository = m.withRepository( this.inviteRepository_ ) @@ -251,9 +251,9 @@ class InviteService extends TransactionBaseService { } async resend(id): Promise { - const inviteRepo = this.manager_.getCustomRepository(InviteRepository) + const inviteRepo = this.manager_.withRepository(InviteRepository) - const invite = await inviteRepo.findOne({ id }) + const invite = await inviteRepo.findOne({ where: { id } }) if (!invite) { throw new MedusaError( diff --git a/packages/medusa/src/services/line-item-adjustment.ts b/packages/medusa/src/services/line-item-adjustment.ts index bf08fea364..08d9f4816c 100644 --- a/packages/medusa/src/services/line-item-adjustment.ts +++ b/packages/medusa/src/services/line-item-adjustment.ts @@ -66,8 +66,9 @@ class LineItemAdjustmentService extends TransactionBaseService { ) } - const lineItemAdjustmentRepo: LineItemAdjustmentRepository = - this.manager_.getCustomRepository(this.lineItemAdjustmentRepo_) + const lineItemAdjustmentRepo = this.manager_.withRepository( + this.lineItemAdjustmentRepo_ + ) const query = buildQuery({ id: lineItemAdjustmentId }, config) const lineItemAdjustment = await lineItemAdjustmentRepo.findOne(query) @@ -89,8 +90,9 @@ class LineItemAdjustmentService extends TransactionBaseService { */ async create(data: Partial): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const lineItemAdjustmentRepo: LineItemAdjustmentRepository = - manager.getCustomRepository(this.lineItemAdjustmentRepo_) + const lineItemAdjustmentRepo = manager.withRepository( + this.lineItemAdjustmentRepo_ + ) const lineItemAdjustment = lineItemAdjustmentRepo.create(data) @@ -109,8 +111,9 @@ class LineItemAdjustmentService extends TransactionBaseService { data: Partial ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const lineItemAdjustmentRepo: LineItemAdjustmentRepository = - manager.getCustomRepository(this.lineItemAdjustmentRepo_) + const lineItemAdjustmentRepo = manager.withRepository( + this.lineItemAdjustmentRepo_ + ) const lineItemAdjustment = await this.retrieve(id) @@ -139,7 +142,7 @@ class LineItemAdjustmentService extends TransactionBaseService { selector: FilterableLineItemAdjustmentProps = {}, config: FindConfig = { skip: 0, take: 20 } ): Promise { - const lineItemAdjustmentRepo = this.manager_.getCustomRepository( + const lineItemAdjustmentRepo = this.manager_.withRepository( this.lineItemAdjustmentRepo_ ) @@ -161,8 +164,9 @@ class LineItemAdjustmentService extends TransactionBaseService { }) ): Promise { return this.atomicPhase_(async (manager) => { - const lineItemAdjustmentRepo: LineItemAdjustmentRepository = - manager.getCustomRepository(this.lineItemAdjustmentRepo_) + const lineItemAdjustmentRepo = manager.withRepository( + this.lineItemAdjustmentRepo_ + ) if (typeof selectorOrIds === "string" || Array.isArray(selectorOrIds)) { const ids = diff --git a/packages/medusa/src/services/line-item.ts b/packages/medusa/src/services/line-item.ts index f1314a31ee..9785a1a86f 100644 --- a/packages/medusa/src/services/line-item.ts +++ b/packages/medusa/src/services/line-item.ts @@ -94,7 +94,7 @@ class LineItemService extends TransactionBaseService { } ): Promise { const manager = this.manager_ - const lineItemRepo = manager.getCustomRepository(this.lineItemRepository_) + const lineItemRepo = manager.withRepository(this.lineItemRepository_) const query = buildQuery(selector, config) return await lineItemRepo.find(query) } @@ -107,9 +107,7 @@ class LineItemService extends TransactionBaseService { */ async retrieve(id: string, config = {}): Promise { const manager = this.manager_ - const lineItemRepository = manager.getCustomRepository( - this.lineItemRepository_ - ) + const lineItemRepository = manager.withRepository(this.lineItemRepository_) const query = buildQuery({ id }, config) @@ -138,11 +136,11 @@ class LineItemService extends TransactionBaseService { ): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const lineItemRepo = transactionManager.getCustomRepository( + const lineItemRepo = transactionManager.withRepository( this.lineItemRepository_ ) - const itemTaxLineRepo = transactionManager.getCustomRepository( + const itemTaxLineRepo = transactionManager.withRepository( this.itemTaxLineRepo_ ) @@ -350,7 +348,7 @@ class LineItemService extends TransactionBaseService { rawLineItem.order_edit_id = context.order_edit_id || null - const lineItemRepo = transactionManager.getCustomRepository( + const lineItemRepo = transactionManager.withRepository( this.lineItemRepository_ ) @@ -371,11 +369,13 @@ class LineItemService extends TransactionBaseService { >(data: T): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const lineItemRepository = transactionManager.getCustomRepository( + const lineItemRepository = transactionManager.withRepository( this.lineItemRepository_ ) - const data_ = Array.isArray(data) ? data : [data] + const data_ = ( + Array.isArray(data) ? data : [data] + ) as DeepPartial[] const items = lineItemRepository.create(data_) const lineItems = await lineItemRepository.save(items) @@ -401,7 +401,7 @@ class LineItemService extends TransactionBaseService { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const lineItemRepository = transactionManager.getCustomRepository( + const lineItemRepository = transactionManager.withRepository( this.lineItemRepository_ ) @@ -436,10 +436,10 @@ class LineItemService extends TransactionBaseService { * @param id - the id of the line item to delete * @return the result of the delete operation */ - async delete(id: string): Promise { + async delete(id: string): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const lineItemRepository = transactionManager.getCustomRepository( + const lineItemRepository = transactionManager.withRepository( this.lineItemRepository_ ) @@ -455,10 +455,10 @@ class LineItemService extends TransactionBaseService { * @param id - the id of the line item to delete * @return the result of the delete operation */ - async deleteWithTaxLines(id: string): Promise { + async deleteWithTaxLines(id: string): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const lineItemRepository = transactionManager.getCustomRepository( + const lineItemRepository = transactionManager.withRepository( this.lineItemRepository_ ) @@ -477,9 +477,7 @@ class LineItemService extends TransactionBaseService { * @return a new line item tax line */ public createTaxLine(args: DeepPartial): LineItemTaxLine { - const itemTaxLineRepo = this.manager_.getCustomRepository( - this.itemTaxLineRepo_ - ) + const itemTaxLineRepo = this.manager_.withRepository(this.itemTaxLineRepo_) return itemTaxLineRepo.create(args) } @@ -502,7 +500,7 @@ class LineItemService extends TransactionBaseService { } ) - const lineItemRepository = manager.getCustomRepository( + const lineItemRepository = manager.withRepository( this.lineItemRepository_ ) diff --git a/packages/medusa/src/services/note.ts b/packages/medusa/src/services/note.ts index c284ff225e..867b5fdf3e 100644 --- a/packages/medusa/src/services/note.ts +++ b/packages/medusa/src/services/note.ts @@ -55,7 +55,7 @@ class NoteService extends TransactionBaseService { ) } - const noteRepo = this.manager_.getCustomRepository(this.noteRepository_) + const noteRepo = this.manager_.withRepository(this.noteRepository_) const query = buildQuery({ id: noteId }, config) @@ -87,7 +87,7 @@ class NoteService extends TransactionBaseService { relations: [], } ): Promise { - const noteRepo = this.manager_.getCustomRepository(this.noteRepository_) + const noteRepo = this.manager_.withRepository(this.noteRepository_) const query = buildQuery(selector, config) @@ -109,7 +109,7 @@ class NoteService extends TransactionBaseService { const { resource_id, resource_type, value, author_id } = data return await this.atomicPhase_(async (manager) => { - const noteRepo = manager.getCustomRepository(this.noteRepository_) + const noteRepo = manager.withRepository(this.noteRepository_) const toCreate = { resource_id, @@ -138,7 +138,7 @@ class NoteService extends TransactionBaseService { */ async update(noteId: string, value: string): Promise { return await this.atomicPhase_(async (manager) => { - const noteRepo = manager.getCustomRepository(this.noteRepository_) + const noteRepo = manager.withRepository(this.noteRepository_) const note = await this.retrieve(noteId, { relations: ["author"] }) @@ -160,7 +160,7 @@ class NoteService extends TransactionBaseService { */ async delete(noteId: string): Promise { return await this.atomicPhase_(async (manager) => { - const noteRepo = manager.getCustomRepository(this.noteRepository_) + const noteRepo = manager.withRepository(this.noteRepository_) const note = await this.retrieve(noteId) diff --git a/packages/medusa/src/services/notification.ts b/packages/medusa/src/services/notification.ts index f5ce8d3716..c22da2e94c 100644 --- a/packages/medusa/src/services/notification.ts +++ b/packages/medusa/src/services/notification.ts @@ -69,7 +69,7 @@ class NotificationService extends TransactionBaseService { */ async registerInstalledProviders(providerIds: string[]): Promise { const { manager, notificationProviderRepository } = this.container_ - const model = manager.getCustomRepository(notificationProviderRepository) + const model = manager.withRepository(notificationProviderRepository) await model.update({}, { is_installed: false }) for (const id of providerIds) { const n = model.create({ id, is_installed: true }) @@ -91,7 +91,7 @@ class NotificationService extends TransactionBaseService { order: { created_at: "DESC" }, } ): Promise { - const notiRepo = this.manager_.getCustomRepository( + const notiRepo = this.manager_.withRepository( this.notificationRepository_ ) const query = buildQuery(selector, config) @@ -108,7 +108,7 @@ class NotificationService extends TransactionBaseService { id: string, config: FindConfig = {} ): Promise { - const notiRepository = this.manager_.getCustomRepository( + const notiRepository = this.manager_.withRepository( this.notificationRepository_ ) @@ -221,7 +221,7 @@ class NotificationService extends TransactionBaseService { } const { to, data } = result - const notiRepo = transactionManager.getCustomRepository( + const notiRepo = transactionManager.withRepository( this.notificationRepository_ ) @@ -265,7 +265,7 @@ class NotificationService extends TransactionBaseService { this.attachmentGenerator_ ) - const notiRepo = transactionManager.getCustomRepository( + const notiRepo = transactionManager.withRepository( this.notificationRepository_ ) const resendNoti: Record = { ...notification, id: null } diff --git a/packages/medusa/src/services/oauth.ts b/packages/medusa/src/services/oauth.ts index 4a79a81eb4..ff62ff7e81 100644 --- a/packages/medusa/src/services/oauth.ts +++ b/packages/medusa/src/services/oauth.ts @@ -39,9 +39,11 @@ class Oauth extends TransactionBaseService { } async retrieveByName(appName: string): Promise { - const repo = this.manager.getCustomRepository(this.oauthRepository_) + const repo = this.manager.withRepository(this.oauthRepository_) const oauth = await repo.findOne({ - application_name: appName, + where: { + application_name: appName, + }, }) if (!oauth) { @@ -62,9 +64,11 @@ class Oauth extends TransactionBaseService { ) } - const repo = this.manager.getCustomRepository(this.oauthRepository_) + const repo = this.manager.withRepository(this.oauthRepository_) const oauth = await repo.findOne({ - id: oauthId, + where: { + id: oauthId, + }, }) if (!oauth) { @@ -78,7 +82,7 @@ class Oauth extends TransactionBaseService { } async list(selector: Selector): Promise { - const repo = this.manager.getCustomRepository(this.oauthRepository_) + const repo = this.manager.withRepository(this.oauthRepository_) const query = buildQuery(selector, {}) @@ -86,7 +90,7 @@ class Oauth extends TransactionBaseService { } async create(data: CreateOauthInput): Promise { - const repo = this.manager.getCustomRepository(this.oauthRepository_) + const repo = this.manager.withRepository(this.oauthRepository_) const application = repo.create({ display_name: data.display_name, @@ -99,7 +103,7 @@ class Oauth extends TransactionBaseService { } async update(id: string, update: UpdateOauthInput): Promise { - const repo = this.manager.getCustomRepository(this.oauthRepository_) + const repo = this.manager.withRepository(this.oauthRepository_) const oauth = await this.retrieve(id) if ("data" in update) { diff --git a/packages/medusa/src/services/order-edit-item-change.ts b/packages/medusa/src/services/order-edit-item-change.ts index da8a9ebae7..847229e85f 100644 --- a/packages/medusa/src/services/order-edit-item-change.ts +++ b/packages/medusa/src/services/order-edit-item-change.ts @@ -53,7 +53,7 @@ export default class OrderEditItemChangeService extends TransactionBaseService { config: FindConfig = {} ): Promise { const manager = this.transactionManager_ ?? this.manager_ - const orderItemChangeRepo = manager.getCustomRepository( + const orderItemChangeRepo = manager.withRepository( this.orderItemChangeRepository_ ) @@ -75,7 +75,7 @@ export default class OrderEditItemChangeService extends TransactionBaseService { config: FindConfig = {} ): Promise { const manager = this.transactionManager_ ?? this.manager_ - const orderItemChangeRepo = manager.getCustomRepository( + const orderItemChangeRepo = manager.withRepository( this.orderItemChangeRepository_ ) @@ -85,7 +85,7 @@ export default class OrderEditItemChangeService extends TransactionBaseService { async create(data: CreateOrderEditItemChangeInput): Promise { return await this.atomicPhase_(async (manager) => { - const orderItemChangeRepo = manager.getCustomRepository( + const orderItemChangeRepo = manager.withRepository( this.orderItemChangeRepository_ ) const changeEntity = orderItemChangeRepo.create(data) @@ -105,7 +105,7 @@ export default class OrderEditItemChangeService extends TransactionBaseService { : [itemChangeIds] return await this.atomicPhase_(async (manager) => { - const orderItemChangeRepo = manager.getCustomRepository( + const orderItemChangeRepo = manager.withRepository( this.orderItemChangeRepository_ ) diff --git a/packages/medusa/src/services/order-edit.ts b/packages/medusa/src/services/order-edit.ts index 4a2d5e9dba..f6812f5a2b 100644 --- a/packages/medusa/src/services/order-edit.ts +++ b/packages/medusa/src/services/order-edit.ts @@ -1,5 +1,11 @@ import { isDefined, MedusaError } from "medusa-core-utils" -import { DeepPartial, EntityManager, ILike, IsNull } from "typeorm" +import { + DeepPartial, + EntityManager, + FindOptionsWhere, + ILike, + IsNull, +} from "typeorm" import { TransactionBaseService } from "../interfaces" import { @@ -104,7 +110,7 @@ export default class OrderEditService extends TransactionBaseService { } const manager = this.transactionManager_ ?? this.manager_ - const orderEditRepository = manager.getCustomRepository( + const orderEditRepository = manager.withRepository( this.orderEditRepository_ ) @@ -126,7 +132,7 @@ export default class OrderEditService extends TransactionBaseService { config?: FindConfig ): Promise<[OrderEdit[], number]> { const manager = this.transactionManager_ ?? this.manager_ - const orderEditRepository = manager.getCustomRepository( + const orderEditRepository = manager.withRepository( this.orderEditRepository_ ) @@ -137,6 +143,7 @@ export default class OrderEditService extends TransactionBaseService { } const query = buildQuery(selector, config) + query.where = query.where as FindOptionsWhere if (q) { query.where.internal_note = ILike(`%${q}%`) @@ -166,7 +173,7 @@ export default class OrderEditService extends TransactionBaseService { ) } - const orderEditRepository = transactionManager.getCustomRepository( + const orderEditRepository = transactionManager.withRepository( this.orderEditRepository_ ) @@ -207,9 +214,7 @@ export default class OrderEditService extends TransactionBaseService { data: DeepPartial ): Promise { return await this.atomicPhase_(async (manager) => { - const orderEditRepo = manager.getCustomRepository( - this.orderEditRepository_ - ) + const orderEditRepo = manager.withRepository(this.orderEditRepository_) const orderEdit = await this.retrieve(orderEditId) @@ -233,9 +238,7 @@ export default class OrderEditService extends TransactionBaseService { async delete(id: string): Promise { return await this.atomicPhase_(async (manager) => { - const orderEditRepo = manager.getCustomRepository( - this.orderEditRepository_ - ) + const orderEditRepo = manager.withRepository(this.orderEditRepository_) const edit = await this.retrieve(id).catch(() => void 0) @@ -263,9 +266,7 @@ export default class OrderEditService extends TransactionBaseService { } ): Promise { return await this.atomicPhase_(async (manager) => { - const orderEditRepo = manager.getCustomRepository( - this.orderEditRepository_ - ) + const orderEditRepo = manager.withRepository(this.orderEditRepository_) const { declinedBy, declinedReason } = context @@ -448,6 +449,7 @@ export default class OrderEditService extends TransactionBaseService { const orderEdit = await this.retrieve(orderEditId, { relations: [ "items", + "items.variant", "items.adjustments", "items.tax_lines", "order", @@ -492,7 +494,12 @@ export default class OrderEditService extends TransactionBaseService { const manager = this.transactionManager_ ?? this.manager_ const { order_id, items } = await this.retrieve(orderEdit.id, { select: ["id", "order_id", "items"], - relations: ["items", "items.tax_lines", "items.adjustments"], + relations: [ + "items", + "items.tax_lines", + "items.adjustments", + "items.variant" + ], }) const orderServiceTx = this.orderService_.withTransaction(manager) @@ -506,6 +513,7 @@ export default class OrderEditService extends TransactionBaseService { "items", "items.tax_lines", "items.adjustments", + "items.variant", "region.tax_rates", "shipping_methods", "shipping_methods.tax_lines", @@ -567,14 +575,15 @@ export default class OrderEditService extends TransactionBaseService { ) let lineItem = await lineItemServiceTx.create(lineItemData) - lineItem = await lineItemServiceTx.retrieve(lineItem.id) + lineItem = await lineItemServiceTx.retrieve(lineItem.id, { + relations: ['variant', 'variant.product'] + }) await this.refreshAdjustments(orderEditId) /** * Generate a change record */ - await this.orderEditItemChangeService_.withTransaction(manager).create({ type: OrderEditItemChangeType.ITEM_ADD, line_item_id: lineItem.id, @@ -584,7 +593,6 @@ export default class OrderEditService extends TransactionBaseService { /** * Compute tax lines */ - const localCart = { ...orderEdit.order, object: "cart", @@ -642,12 +650,14 @@ export default class OrderEditService extends TransactionBaseService { } = {} ): Promise { return await this.atomicPhase_(async (manager) => { - const orderEditRepo = manager.getCustomRepository( - this.orderEditRepository_ - ) + const orderEditRepo = manager.withRepository(this.orderEditRepository_) let orderEdit = await this.retrieve(orderEditId, { - relations: ["changes"], + relations: [ + "changes", + "changes.original_line_item", + "changes.original_line_item.variant", + ], select: ["id", "order_id", "requested_at"], }) @@ -680,7 +690,7 @@ export default class OrderEditService extends TransactionBaseService { context: { canceledBy?: string } = {} ): Promise { return await this.atomicPhase_(async (manager) => { - const orderEditRepository = manager.getCustomRepository( + const orderEditRepository = manager.withRepository( this.orderEditRepository_ ) @@ -719,7 +729,7 @@ export default class OrderEditService extends TransactionBaseService { context: { confirmedBy?: string } = {} ): Promise { return await this.atomicPhase_(async (manager) => { - const orderEditRepository = manager.getCustomRepository( + const orderEditRepository = manager.withRepository( this.orderEditRepository_ ) @@ -769,9 +779,9 @@ export default class OrderEditService extends TransactionBaseService { protected async retrieveActive( orderId: string, config: FindConfig = {} - ): Promise { + ): Promise { const manager = this.transactionManager_ ?? this.manager_ - const orderEditRepository = manager.getCustomRepository( + const orderEditRepository = manager.withRepository( this.orderEditRepository_ ) @@ -808,7 +818,11 @@ export default class OrderEditService extends TransactionBaseService { const orderEdit = await this.retrieve(orderEditId, { select: ["id", "changes"], - relations: ["changes"], + relations: [ + "changes", + "changes.original_line_item", + "changes.original_line_item.variant" + ], }) await this.orderEditItemChangeService_.delete( diff --git a/packages/medusa/src/services/order.ts b/packages/medusa/src/services/order.ts index 5bea5d912e..9417ad89e2 100644 --- a/packages/medusa/src/services/order.ts +++ b/packages/medusa/src/services/order.ts @@ -1,5 +1,13 @@ import { isDefined, MedusaError } from "medusa-core-utils" -import { Brackets, EntityManager } from "typeorm" +import { + EntityManager, + FindManyOptions, + FindOptionsWhere, + ILike, + IsNull, + Not, + Raw, +} from "typeorm" import { TransactionBaseService } from "../interfaces" import SalesChannelFeatureFlag from "../loaders/feature-flags/sales-channels" import { @@ -28,7 +36,13 @@ import { } from "../types/fulfillment" import { UpdateOrderInput } from "../types/orders" import { CreateShippingMethodDto } from "../types/shipping-options" -import { buildQuery, isString, setMetadata } from "../utils" +import { + buildQuery, + buildRelations, + buildSelects, + isString, + setMetadata, +} from "../utils" import { FlagRouter } from "../utils/flag-router" import { @@ -205,53 +219,92 @@ class OrderService extends TransactionBaseService { order: { created_at: "DESC" }, } ): Promise<[Order[], number]> { - const orderRepo = this.manager_.getCustomRepository(this.orderRepository_) + const orderRepo = this.manager_.withRepository(this.orderRepository_) let q if (selector.q) { q = selector.q delete selector.q + + config.relations = config.relations + ? Array.from( + new Set([...config.relations, "shipping_address", "customer"]) + ) + : ["shipping_address", "customer"] } - const query = buildQuery(selector, config) + const query = buildQuery(selector, config) as FindManyOptions if (q) { - const where = query.where + const where = query.where as FindOptionsWhere delete where.display_id delete where.email - query.join = { - alias: "order", - innerJoin: { - shipping_address: "order.shipping_address", - customer: "order.customer", + // Inner join like constraints + const innerJoinLikeConstraints = { + customer: { + id: Not(IsNull()), + }, + shipping_address: { + id: Not(IsNull()), }, } - query.where = (qb): void => { - qb.where(where) - - qb.andWhere( - new Brackets((qb) => { - qb.where(`shipping_address.first_name ILIKE :qfn`, { - qfn: `%${q}%`, - }) - .orWhere(`order.email ILIKE :q`, { q: `%${q}%` }) - .orWhere(`display_id::varchar(255) ILIKE :dId`, { dId: `${q}` }) - .orWhere(`customer.first_name ILIKE :q`, { q: `%${q}%` }) - .orWhere(`customer.last_name ILIKE :q`, { q: `%${q}%` }) - .orWhere(`customer.phone ILIKE :q`, { q: `%${q}%` }) - }) - ) - } + query.where = [ + { + ...query.where, + ...innerJoinLikeConstraints, + shipping_address: { + ...innerJoinLikeConstraints.shipping_address, + id: Not(IsNull()), + first_name: ILike(`%${q}%`), + }, + }, + { + ...query.where, + ...innerJoinLikeConstraints, + email: ILike(`%${q}%`), + }, + { + ...query.where, + ...innerJoinLikeConstraints, + display_id: Raw((alias) => `CAST(${alias} as varchar) ILike :q`, { + q: `%${q}%`, + }), + }, + { + ...query.where, + ...innerJoinLikeConstraints, + customer: { + ...innerJoinLikeConstraints.customer, + first_name: ILike(`%${q}%`), + }, + }, + { + ...query.where, + ...innerJoinLikeConstraints, + customer: { + ...innerJoinLikeConstraints.customer, + last_name: ILike(`%${q}%`), + }, + }, + { + ...query.where, + ...innerJoinLikeConstraints, + customer: { + ...innerJoinLikeConstraints.customer, + phone: ILike(`%${q}%`), + }, + }, + ] } const { select, relations, totalsToSelect } = this.transformQueryForTotals(config) - query.select = select - const rels = this.getTotalsRelations({ relations }) + query.select = buildSelects(select || []) + const rels = buildRelations(this.getTotalsRelations({ relations })) delete query.relations @@ -300,6 +353,8 @@ class OrderService extends TransactionBaseService { relationSet.add("items") relationSet.add("items.tax_lines") relationSet.add("items.adjustments") + relationSet.add("items.variant") + relationSet.add("items.variant.product") relationSet.add("swaps") relationSet.add("swaps.additional_items") relationSet.add("swaps.additional_items.tax_lines") @@ -358,7 +413,7 @@ class OrderService extends TransactionBaseService { } const manager = this.manager_ - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) const query = buildQuery({ id: orderId }, config) @@ -366,8 +421,8 @@ class OrderService extends TransactionBaseService { query.select = undefined } - const queryRelations = query.relations - query.relations = undefined + const queryRelations = { ...query.relations } + delete query.relations const raw = await orderRepo.findOneWithRelations(queryRelations, query) @@ -385,7 +440,7 @@ class OrderService extends TransactionBaseService { orderIdOrSelector: string | Selector, config: FindConfig = {} ): Promise { - const orderRepo = this.manager_.getCustomRepository(this.orderRepository_) + const orderRepo = this.manager_.withRepository(this.orderRepository_) const { select, relations, totalsToSelect } = this.transformQueryForTotals(config) @@ -393,13 +448,14 @@ class OrderService extends TransactionBaseService { const selector = isString(orderIdOrSelector) ? { id: orderIdOrSelector } : orderIdOrSelector + const query = buildQuery(selector, config) if (relations && relations.length > 0) { - query.relations = relations + query.relations = buildRelations(relations) } - query.select = select?.length ? select : undefined + query.select = select?.length ? buildSelects(select) : undefined const rels = query.relations delete query.relations @@ -440,7 +496,7 @@ class OrderService extends TransactionBaseService { cartId: string, config: FindConfig = {} ): Promise { - const orderRepo = this.manager_.getCustomRepository(this.orderRepository_) + const orderRepo = this.manager_.withRepository(this.orderRepository_) const { select, relations, totalsToSelect } = this.transformQueryForTotals(config) @@ -481,24 +537,31 @@ class OrderService extends TransactionBaseService { externalId: string, config: FindConfig = {} ): Promise { - const orderRepo = this.manager_.getCustomRepository(this.orderRepository_) + const orderRepo = this.manager_.withRepository(this.orderRepository_) const { select, relations, totalsToSelect } = this.transformQueryForTotals(config) - const query = { + const selector = { where: { external_id: externalId }, - } as FindConfig - - if (relations && relations.length > 0) { - query.relations = relations } - query.relations = this.getTotalsRelations({ relations: query.relations }) - query.select = select?.length ? select : undefined + let queryRelations + if (relations && relations.length > 0) { + queryRelations = relations + } + queryRelations = this.getTotalsRelations({ relations: queryRelations }) - const rels = query.relations + const querySelect = select?.length ? select : undefined + + const query = buildQuery(selector, { + select: querySelect, + relations: queryRelations, + } as FindConfig) + + const rels = { ...query.relations } delete query.relations + const raw = await orderRepo.findOneWithRelations(rels, query) if (!raw) { throw new MedusaError( @@ -532,7 +595,7 @@ class OrderService extends TransactionBaseService { order.status = OrderStatus.COMPLETED - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) return orderRepo.save(order) }) } @@ -597,7 +660,7 @@ class OrderService extends TransactionBaseService { } } - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) // TODO: Due to cascade insert we have to remove the tax_lines that have been added by the cart decorate totals. // Is the cascade insert really used? Also, is it really necessary to pass the entire entities when creating or updating? @@ -853,7 +916,7 @@ class OrderService extends TransactionBaseService { } } - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) const result = await orderRepo.save(order) await this.eventBus_ @@ -878,7 +941,7 @@ class OrderService extends TransactionBaseService { order: Order, address: Address ): Promise { - const addrRepo = this.manager_.getCustomRepository(this.addressRepository_) + const addrRepo = this.manager_.withRepository(this.addressRepository_) address.country_code = address.country_code?.toLowerCase() ?? null const region = await this.regionService_ @@ -917,7 +980,7 @@ class OrderService extends TransactionBaseService { order: Order, address: Address ): Promise { - const addrRepo = this.manager_.getCustomRepository(this.addressRepository_) + const addrRepo = this.manager_.withRepository(this.addressRepository_) address.country_code = address.country_code?.toLowerCase() ?? null const region = await this.regionService_ @@ -1076,7 +1139,7 @@ class OrderService extends TransactionBaseService { order[key] = value } - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) const result = await orderRepo.save(order) await this.eventBus_ @@ -1167,7 +1230,7 @@ class OrderService extends TransactionBaseService { order.payment_status = PaymentStatus.CANCELED order.canceled_at = new Date() - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) const result = await orderRepo.save(order) await this.eventBus_ @@ -1187,7 +1250,7 @@ class OrderService extends TransactionBaseService { */ async capturePayment(orderId: string): Promise { return await this.atomicPhase_(async (manager) => { - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) const order = await this.retrieve(orderId, { relations: ["payments"] }) if (order.status === "canceled") { @@ -1391,7 +1454,7 @@ class OrderService extends TransactionBaseService { } } } - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) order.fulfillments = [...order.fulfillments, ...fulfillments] @@ -1435,7 +1498,7 @@ class OrderService extends TransactionBaseService { order.fulfillment_status = FulfillmentStatus.CANCELED - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) const updated = await orderRepo.save(order) await this.eventBus_ @@ -1493,7 +1556,7 @@ class OrderService extends TransactionBaseService { } order.status = OrderStatus.ARCHIVED - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) return await orderRepo.save(order) }) } @@ -1519,7 +1582,7 @@ class OrderService extends TransactionBaseService { const { no_notification } = config return await this.atomicPhase_(async (manager) => { - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) const order = await this.retrieve(orderId, { select: ["refundable_amount", "total", "refunded_total"], @@ -1885,7 +1948,7 @@ class OrderService extends TransactionBaseService { const refundAmount = customRefundAmount ?? receivedReturn.refund_amount - const orderRepo = manager.getCustomRepository(this.orderRepository_) + const orderRepo = manager.withRepository(this.orderRepository_) if (refundAmount > order.refundable_amount) { order.fulfillment_status = FulfillmentStatus.REQUIRES_ACTION diff --git a/packages/medusa/src/services/payment-collection.ts b/packages/medusa/src/services/payment-collection.ts index d42d8b62d9..f3bfc07d08 100644 --- a/packages/medusa/src/services/payment-collection.ts +++ b/packages/medusa/src/services/payment-collection.ts @@ -83,7 +83,7 @@ export default class PaymentCollectionService extends TransactionBaseService { } const manager = this.transactionManager_ ?? this.manager_ - const paymentCollectionRepository = manager.getCustomRepository( + const paymentCollectionRepository = manager.withRepository( this.paymentCollectionRepository_ ) @@ -110,7 +110,7 @@ export default class PaymentCollectionService extends TransactionBaseService { */ async create(data: CreatePaymentCollectionInput): Promise { return await this.atomicPhase_(async (manager) => { - const paymentCollectionRepository = manager.getCustomRepository( + const paymentCollectionRepository = manager.withRepository( this.paymentCollectionRepository_ ) @@ -148,7 +148,7 @@ export default class PaymentCollectionService extends TransactionBaseService { data: DeepPartial ): Promise { return await this.atomicPhase_(async (manager) => { - const paymentCollectionRepo = manager.getCustomRepository( + const paymentCollectionRepo = manager.withRepository( this.paymentCollectionRepository_ ) @@ -181,7 +181,7 @@ export default class PaymentCollectionService extends TransactionBaseService { paymentCollectionId: string ): Promise { return await this.atomicPhase_(async (manager) => { - const paymentCollectionRepo = manager.getCustomRepository( + const paymentCollectionRepo = manager.withRepository( this.paymentCollectionRepository_ ) @@ -236,7 +236,7 @@ export default class PaymentCollectionService extends TransactionBaseService { customerId: string ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const paymentCollectionRepository = manager.getCustomRepository( + const paymentCollectionRepository = manager.withRepository( this.paymentCollectionRepository_ ) @@ -417,7 +417,7 @@ export default class PaymentCollectionService extends TransactionBaseService { customerId: string ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const paymentCollectionRepository = manager.getCustomRepository( + const paymentCollectionRepository = manager.withRepository( this.paymentCollectionRepository_ ) @@ -507,7 +507,7 @@ export default class PaymentCollectionService extends TransactionBaseService { paymentCollectionId: string ): Promise { return await this.atomicPhase_(async (manager) => { - const paymentCollectionRepo = manager.getCustomRepository( + const paymentCollectionRepo = manager.withRepository( this.paymentCollectionRepository_ ) @@ -538,7 +538,7 @@ export default class PaymentCollectionService extends TransactionBaseService { context: Record = {} ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const paymentCollectionRepository = manager.getCustomRepository( + const paymentCollectionRepository = manager.withRepository( this.paymentCollectionRepository_ ) diff --git a/packages/medusa/src/services/payment-provider.ts b/packages/medusa/src/services/payment-provider.ts index e3d68b15b4..53ec886f60 100644 --- a/packages/medusa/src/services/payment-provider.ts +++ b/packages/medusa/src/services/payment-provider.ts @@ -77,7 +77,7 @@ export default class PaymentProviderService extends TransactionBaseService { async registerInstalledProviders(providerIds: string[]): Promise { return await this.atomicPhase_(async (transactionManager) => { - const model = transactionManager.getCustomRepository( + const model = transactionManager.withRepository( this.paymentProviderRepository_ ) await model.update({}, { is_installed: false }) @@ -95,7 +95,7 @@ export default class PaymentProviderService extends TransactionBaseService { } async list(): Promise { - const ppRepo = this.manager_.getCustomRepository( + const ppRepo = this.manager_.withRepository( this.paymentProviderRepository_ ) return await ppRepo.find() @@ -105,7 +105,7 @@ export default class PaymentProviderService extends TransactionBaseService { id: string, relations: string[] = [] ): Promise { - const paymentRepo = this.manager_.getCustomRepository( + const paymentRepo = this.manager_.withRepository( this.paymentRepository_ ) const query = { @@ -137,7 +137,7 @@ export default class PaymentProviderService extends TransactionBaseService { order: { created_at: "DESC" }, } ): Promise { - const payRepo = this.manager_.getCustomRepository(this.paymentRepository_) + const payRepo = this.manager_.withRepository(this.paymentRepository_) const query = buildQuery(selector, config) return await payRepo.find(query) } @@ -146,7 +146,7 @@ export default class PaymentProviderService extends TransactionBaseService { id: string, relations: string[] = [] ): Promise { - const sessionRepo = this.manager_.getCustomRepository( + const sessionRepo = this.manager_.withRepository( this.paymentSessionRepository_ ) @@ -250,7 +250,7 @@ export default class PaymentProviderService extends TransactionBaseService { ) await provider.withTransaction(transactionManager).deletePayment(session) - const sessionRepo = transactionManager.getCustomRepository( + const sessionRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) @@ -317,7 +317,7 @@ export default class PaymentProviderService extends TransactionBaseService { .withTransaction(transactionManager) .deletePayment(paymentSession) - const sessionRepo = transactionManager.getCustomRepository( + const sessionRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) @@ -364,7 +364,7 @@ export default class PaymentProviderService extends TransactionBaseService { .withTransaction(transactionManager) .getPaymentData(payment_session) - const paymentRepo = transactionManager.getCustomRepository( + const paymentRepo = transactionManager.withRepository( this.paymentRepository_ ) @@ -417,7 +417,7 @@ export default class PaymentProviderService extends TransactionBaseService { session.payment_authorized_at = new Date() } - const sessionRepo = transactionManager.getCustomRepository( + const sessionRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) return await sessionRepo.save(session) @@ -438,7 +438,7 @@ export default class PaymentProviderService extends TransactionBaseService { .updatePaymentData(paymentSession.data, data) session.status = paymentSession.status - const sessionRepo = transactionManager.getCustomRepository( + const sessionRepo = transactionManager.withRepository( this.paymentSessionRepository_ ) return await sessionRepo.save(session) @@ -458,7 +458,7 @@ export default class PaymentProviderService extends TransactionBaseService { const now = new Date() payment.canceled_at = now.toISOString() - const paymentRepo = transactionManager.getCustomRepository( + const paymentRepo = transactionManager.withRepository( this.paymentRepository_ ) return await paymentRepo.save(payment) @@ -483,7 +483,7 @@ export default class PaymentProviderService extends TransactionBaseService { const now = new Date() payment.captured_at = now.toISOString() - const paymentRepo = transactionManager.getCustomRepository( + const paymentRepo = transactionManager.withRepository( this.paymentRepository_ ) return await paymentRepo.save(payment) @@ -522,7 +522,7 @@ export default class PaymentProviderService extends TransactionBaseService { const used: string[] = [] - const paymentRepo = transactionManager.getCustomRepository( + const paymentRepo = transactionManager.withRepository( this.paymentRepository_ ) @@ -559,7 +559,7 @@ export default class PaymentProviderService extends TransactionBaseService { } } - const refundRepo = transactionManager.getCustomRepository( + const refundRepo = transactionManager.withRepository( this.refundRepository_ ) @@ -598,10 +598,10 @@ export default class PaymentProviderService extends TransactionBaseService { payment.amount_refunded += amount - const paymentRepo = manager.getCustomRepository(this.paymentRepository_) + const paymentRepo = manager.withRepository(this.paymentRepository_) await paymentRepo.save(payment) - const refundRepo = manager.getCustomRepository(this.refundRepository_) + const refundRepo = manager.withRepository(this.refundRepository_) const toCreate = { payment_id: payment.id, @@ -619,7 +619,7 @@ export default class PaymentProviderService extends TransactionBaseService { id: string, config: FindConfig = {} ): Promise { - const refRepo = this.manager_.getCustomRepository(this.refundRepository_) + const refRepo = this.manager_.withRepository(this.refundRepository_) const query = buildQuery({ id }, config) const refund = await refRepo.findOne(query) @@ -692,7 +692,7 @@ export default class PaymentProviderService extends TransactionBaseService { ): Promise { const manager = this.transactionManager_ ?? this.manager_ - const sessionRepo = manager.getCustomRepository( + const sessionRepo = manager.withRepository( this.paymentSessionRepository_ ) diff --git a/packages/medusa/src/services/payment.ts b/packages/medusa/src/services/payment.ts index 5c5b1473e6..08c495aa72 100644 --- a/packages/medusa/src/services/payment.ts +++ b/packages/medusa/src/services/payment.ts @@ -70,7 +70,7 @@ export default class PaymentService extends TransactionBaseService { } const manager = this.transactionManager_ ?? this.manager_ - const paymentRepository = manager.getCustomRepository( + const paymentRepository = manager.withRepository( this.paymentRepository_ ) @@ -97,7 +97,7 @@ export default class PaymentService extends TransactionBaseService { return await this.atomicPhase_(async (manager: EntityManager) => { const { data, currency_code, amount, provider_id } = paymentInput - const paymentRepository = manager.getCustomRepository( + const paymentRepository = manager.withRepository( this.paymentRepository_ ) @@ -131,7 +131,7 @@ export default class PaymentService extends TransactionBaseService { return await this.atomicPhase_(async (manager: EntityManager) => { const payment = await this.retrieve(paymentId) - const paymentRepository = manager.getCustomRepository( + const paymentRepository = manager.withRepository( this.paymentRepository_ ) diff --git a/packages/medusa/src/services/price-list.ts b/packages/medusa/src/services/price-list.ts index 8dca976944..a3a1554c92 100644 --- a/packages/medusa/src/services/price-list.ts +++ b/packages/medusa/src/services/price-list.ts @@ -1,13 +1,18 @@ import { isDefined, MedusaError } from "medusa-core-utils" -import { DeepPartial, EntityManager, FindOperator } from "typeorm" +import { + DeepPartial, + EntityManager, + FindManyOptions, + FindOperator, + FindOptionsWhere, + ILike, + In, +} from "typeorm" import { CustomerGroupService } from "." import { CustomerGroup, PriceList, Product, ProductVariant } from "../models" import { MoneyAmountRepository } from "../repositories/money-amount" -import { - PriceListFindOptions, - PriceListRepository, -} from "../repositories/price-list" -import { FindConfig, Selector } from "../types/common" +import { PriceListRepository } from "../repositories/price-list" +import { ExtendedFindConfig, FindConfig, Selector } from "../types/common" import { CreatePriceListInput, FilterablePriceListProps, @@ -96,7 +101,7 @@ class PriceListService extends TransactionBaseService { ) } - const priceListRepo = this.manager_.getCustomRepository(this.priceListRepo_) + const priceListRepo = this.manager_.withRepository(this.priceListRepo_) const query = buildQuery({ id: priceListId }, config) const priceList = await priceListRepo.findOne(query) @@ -120,8 +125,8 @@ class PriceListService extends TransactionBaseService { priceListObject: CreatePriceListInput ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const priceListRepo = manager.getCustomRepository(this.priceListRepo_) - const moneyAmountRepo = manager.getCustomRepository(this.moneyAmountRepo_) + const priceListRepo = manager.withRepository(this.priceListRepo_) + const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) const { prices, customer_groups, includes_tax, ...rest } = priceListObject @@ -166,8 +171,8 @@ class PriceListService extends TransactionBaseService { */ async update(id: string, update: UpdatePriceListInput): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const priceListRepo = manager.getCustomRepository(this.priceListRepo_) - const moneyAmountRepo = manager.getCustomRepository(this.moneyAmountRepo_) + const priceListRepo = manager.withRepository(this.priceListRepo_) + const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) const priceList = await this.retrieve(id, { select: ["id"] }) @@ -221,7 +226,7 @@ class PriceListService extends TransactionBaseService { replace = false ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.getCustomRepository(this.moneyAmountRepo_) + const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) const priceList = await this.retrieve(id, { select: ["id"] }) @@ -242,7 +247,7 @@ class PriceListService extends TransactionBaseService { */ async deletePrices(id: string, priceIds: string[]): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.getCustomRepository(this.moneyAmountRepo_) + const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) const priceList = await this.retrieve(id, { select: ["id"] }) @@ -257,7 +262,7 @@ class PriceListService extends TransactionBaseService { */ async clearPrices(id: string): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.getCustomRepository(this.moneyAmountRepo_) + const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) const priceList = await this.retrieve(id, { select: ["id"] }) await moneyAmountRepo.delete({ price_list_id: priceList.id }) }) @@ -271,7 +276,7 @@ class PriceListService extends TransactionBaseService { */ async delete(id: string): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const priceListRepo = manager.getCustomRepository(this.priceListRepo_) + const priceListRepo = manager.withRepository(this.priceListRepo_) const priceList = await priceListRepo.findOne({ where: { id: id } }) @@ -294,15 +299,20 @@ class PriceListService extends TransactionBaseService { config: FindConfig = { skip: 0, take: 20 } ): Promise { const manager = this.manager_ - const priceListRepo = manager.getCustomRepository(this.priceListRepo_) + const priceListRepo = manager.withRepository(this.priceListRepo_) const { q, ...priceListSelector } = selector - const query = buildQuery(priceListSelector, config) + const query = buildQuery( + priceListSelector, + config + ) as FindManyOptions & { + where: { customer_groups?: FindOperator } + } & ExtendedFindConfig - const groups = query.where.customer_groups as FindOperator + const groups = query.where.customer_groups query.where.customer_groups = undefined - const [priceLists] = await priceListRepo.listAndCount(query, groups) + const [priceLists] = await priceListRepo.listAndCount(query as any) return priceLists } @@ -315,38 +325,71 @@ class PriceListService extends TransactionBaseService { */ async listAndCount( selector: FilterablePriceListProps = {}, - config: FindConfig = { + config: FindConfig = { skip: 0, take: 20, } ): Promise<[PriceList[], number]> { const manager = this.manager_ - const priceListRepo = manager.getCustomRepository(this.priceListRepo_) + const priceListRepo = manager.withRepository(this.priceListRepo_) const { q, ...priceListSelector } = selector - const { relations, ...query } = buildQuery< - FilterablePriceListProps, - FilterablePriceListProps - >(priceListSelector, config) + const query = buildQuery(priceListSelector, config) + query.where = query.where as FindOptionsWhere - const groups = query.where.customer_groups as FindOperator + const groups = query.where.customer_groups as unknown as FindOperator< + string[] + > delete query.where.customer_groups - if (q) { - return await priceListRepo.getFreeTextSearchResultsAndCount( - q, - query as PriceListFindOptions, - groups, - relations - ) + if (groups) { + query.relations = query.relations ?? {} + query.relations.customer_groups = query.relations.customer_groups ?? true + + query.where.customer_groups = { + ...(query.where.customer_groups ?? {}), + id: In(groups.value), + } } - return await priceListRepo.listAndCount({ ...query, relations }, groups) + + if (q) { + if (!groups) { + query.relations = query.relations ?? {} + query.relations.customer_groups = + query.relations.customer_groups ?? true + } + + const where = [ + { + ...query.where, + name: ILike(`%${q}%`), + }, + { + ...query.where, + description: ILike(`%${q}%`), + }, + { + ...query.where, + customer_groups: { + ...query.where.customer_groups, + name: ILike(`%${q}%`), + }, + }, + ] + + return await priceListRepo.findAndCount({ + ...query, + where, + }) + } + + return await priceListRepo.listAndCount(query) } protected async upsertCustomerGroups_( priceListId: string, customerGroups: { id: string }[] ): Promise { - const priceListRepo = this.manager_.getCustomRepository(this.priceListRepo_) + const priceListRepo = this.manager_.withRepository(this.priceListRepo_) const priceList = await this.retrieve(priceListId, { select: ["id"] }) const groups: CustomerGroup[] = [] @@ -372,14 +415,14 @@ class PriceListService extends TransactionBaseService { requiresPriceList = false ): Promise<[Product[], number]> { return await this.atomicPhase_(async (manager: EntityManager) => { - const productVariantRepo = manager.getCustomRepository( + const productVariantRepo = manager.withRepository( this.productVariantRepo_ ) const [products, count] = await this.productService_ .withTransaction(manager) .listAndCount(selector, config) - const moneyAmountRepo = manager.getCustomRepository(this.moneyAmountRepo_) + const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) const productsWithPrices = await Promise.all( products.map(async (p) => { @@ -424,7 +467,7 @@ class PriceListService extends TransactionBaseService { .withTransaction(manager) .listAndCount(selector, config) - const moneyAmountRepo = manager.getCustomRepository(this.moneyAmountRepo_) + const moneyAmountRepo = manager.withRepository(this.moneyAmountRepo_) const variantsWithPrices = await Promise.all( variants.map(async (variant) => { diff --git a/packages/medusa/src/services/product-category.ts b/packages/medusa/src/services/product-category.ts index 60082d133a..ed48259de4 100644 --- a/packages/medusa/src/services/product-category.ts +++ b/packages/medusa/src/services/product-category.ts @@ -62,7 +62,7 @@ class ProductCategoryService extends TransactionBaseService { treeSelector: QuerySelector = {} ): Promise<[ProductCategory[], number]> { const manager = this.transactionManager_ ?? this.manager_ - const productCategoryRepo = manager.getCustomRepository( + const productCategoryRepo = manager.withRepository( this.productCategoryRepo_ ) @@ -103,7 +103,7 @@ class ProductCategoryService extends TransactionBaseService { const selectors = Object.assign({ id: productCategoryId }, selector) const query = buildQuery(selectors, config) - const productCategoryRepo = this.manager_.getCustomRepository( + const productCategoryRepo = this.manager_.withRepository( this.productCategoryRepo_ ) @@ -133,7 +133,7 @@ class ProductCategoryService extends TransactionBaseService { productCategoryInput: CreateProductCategoryInput ): Promise { return await this.atomicPhase_(async (manager) => { - const pcRepo = manager.getCustomRepository(this.productCategoryRepo_) + const pcRepo = manager.withRepository(this.productCategoryRepo_) let productCategory = pcRepo.create(productCategoryInput) productCategory = await pcRepo.save(productCategory) @@ -158,7 +158,7 @@ class ProductCategoryService extends TransactionBaseService { productCategoryInput: UpdateProductCategoryInput ): Promise { return await this.atomicPhase_(async (manager) => { - const productCategoryRepo = manager.getCustomRepository( + const productCategoryRepo = manager.withRepository( this.productCategoryRepo_ ) @@ -190,8 +190,8 @@ class ProductCategoryService extends TransactionBaseService { */ async delete(productCategoryId: string): Promise { return await this.atomicPhase_(async (manager) => { - const productCategoryRepository: ProductCategoryRepository = - manager.getCustomRepository(this.productCategoryRepo_) + const productCategoryRepository: typeof ProductCategoryRepository = + manager.withRepository(this.productCategoryRepo_) const productCategory = await this.retrieve(productCategoryId, { relations: ["category_children"], @@ -229,8 +229,8 @@ class ProductCategoryService extends TransactionBaseService { productIds: string[] ): Promise { return await this.atomicPhase_(async (manager) => { - const productCategoryRepository: ProductCategoryRepository = - manager.getCustomRepository(this.productCategoryRepo_) + const productCategoryRepository = + manager.withRepository(this.productCategoryRepo_) await productCategoryRepository.addProducts(productCategoryId, productIds) }) @@ -247,8 +247,8 @@ class ProductCategoryService extends TransactionBaseService { productIds: string[] ): Promise { return await this.atomicPhase_(async (manager) => { - const productCategoryRepository: ProductCategoryRepository = - manager.getCustomRepository(this.productCategoryRepo_) + const productCategoryRepository = + manager.withRepository(this.productCategoryRepo_) await productCategoryRepository.removeProducts( productCategoryId, diff --git a/packages/medusa/src/services/product-collection.ts b/packages/medusa/src/services/product-collection.ts index a34a3668ae..352aa320ee 100644 --- a/packages/medusa/src/services/product-collection.ts +++ b/packages/medusa/src/services/product-collection.ts @@ -1,10 +1,15 @@ import { isDefined, MedusaError } from "medusa-core-utils" -import { Brackets, EntityManager, ILike } from "typeorm" +import { + EntityManager, + FindManyOptions, + FindOptionsWhere, + ILike, +} from "typeorm" import { TransactionBaseService } from "../interfaces" import { ProductCollection } from "../models" import { ProductRepository } from "../repositories/product" import { ProductCollectionRepository } from "../repositories/product-collection" -import { FindConfig, Selector } from "../types/common" +import { ExtendedFindConfig, FindConfig, Selector } from "../types/common" import { CreateProductCollection, UpdateProductCollection, @@ -19,6 +24,11 @@ type InjectedDependencies = { productCollectionRepository: typeof ProductCollectionRepository } +type ListAndCountSelector = Selector & { + q?: string + discount_condition_id?: string +} + /** * Provides layer to manipulate product collections. */ @@ -62,7 +72,7 @@ class ProductCollectionService extends TransactionBaseService { ) } - const collectionRepo = this.manager_.getCustomRepository( + const collectionRepo = this.manager_.withRepository( this.productCollectionRepository_ ) @@ -89,7 +99,7 @@ class ProductCollectionService extends TransactionBaseService { collectionHandle: string, config: FindConfig = {} ): Promise { - const collectionRepo = this.manager_.getCustomRepository( + const collectionRepo = this.manager_.withRepository( this.productCollectionRepository_ ) @@ -115,7 +125,7 @@ class ProductCollectionService extends TransactionBaseService { collection: CreateProductCollection ): Promise { return await this.atomicPhase_(async (manager) => { - const collectionRepo = manager.getCustomRepository( + const collectionRepo = manager.withRepository( this.productCollectionRepository_ ) @@ -135,7 +145,7 @@ class ProductCollectionService extends TransactionBaseService { update: UpdateProductCollection ): Promise { return await this.atomicPhase_(async (manager) => { - const collectionRepo = manager.getCustomRepository( + const collectionRepo = manager.withRepository( this.productCollectionRepository_ ) @@ -162,7 +172,7 @@ class ProductCollectionService extends TransactionBaseService { */ async delete(collectionId: string): Promise { return await this.atomicPhase_(async (manager) => { - const productCollectionRepo = manager.getCustomRepository( + const productCollectionRepo = manager.withRepository( this.productCollectionRepository_ ) @@ -183,7 +193,7 @@ class ProductCollectionService extends TransactionBaseService { productIds: string[] ): Promise { return await this.atomicPhase_(async (manager) => { - const productRepo = manager.getCustomRepository(this.productRepository_) + const productRepo = manager.withRepository(this.productRepository_) const { id } = await this.retrieve(collectionId, { select: ["id"] }) @@ -200,7 +210,7 @@ class ProductCollectionService extends TransactionBaseService { productIds: string[] ): Promise { return await this.atomicPhase_(async (manager) => { - const productRepo = manager.getCustomRepository(this.productRepository_) + const productRepo = manager.withRepository(this.productRepository_) const { id } = await this.retrieve(collectionId, { select: ["id"] }) @@ -234,13 +244,10 @@ class ProductCollectionService extends TransactionBaseService { * @return the result of the find operation */ async listAndCount( - selector: Selector & { - q?: string - discount_condition_id?: string - } = {}, + selector: ListAndCountSelector = {}, config: FindConfig = { skip: 0, take: 20 } ): Promise<[ProductCollection[], number]> { - const productCollectionRepo = this.manager_.getCustomRepository( + const productCollectionRepo = this.manager_.withRepository( this.productCollectionRepository_ ) @@ -250,31 +257,35 @@ class ProductCollectionService extends TransactionBaseService { delete selector.q } - const query = buildQuery(selector, config) + const query = buildQuery( + selector, + config + ) as FindManyOptions & { + where: { discount_condition_id?: string } + } & ExtendedFindConfig if (q) { - const where = query.where + const where = query.where as FindOptionsWhere delete where.title delete where.handle delete where.created_at delete where.updated_at - query.where = (qb): void => { - qb.where(where) - - qb.andWhere( - new Brackets((qb) => { - qb.where({ title: ILike(`%${q}%`) }).orWhere({ - handle: ILike(`%${q}%`), - }) - }) - ) - } + query.where = [ + { + ...where, + title: ILike(`%${q}%`), + }, + { + ...where, + handle: ILike(`%${q}%`), + }, + ] } if (query.where.discount_condition_id) { - const discountConditionId = query.where.discount_condition_id as string + const discountConditionId = query.where.discount_condition_id delete query.where.discount_condition_id return await productCollectionRepo.findAndCountByDiscountConditionId( discountConditionId, diff --git a/packages/medusa/src/services/product-tag.ts b/packages/medusa/src/services/product-tag.ts index 89b1fcfbb4..6188d276b4 100644 --- a/packages/medusa/src/services/product-tag.ts +++ b/packages/medusa/src/services/product-tag.ts @@ -1,5 +1,5 @@ import { MedusaError } from "medusa-core-utils" -import { EntityManager, ILike } from "typeorm" +import { EntityManager, FindOptionsWhere, ILike } from "typeorm" import { ProductTag } from "../models" import { ProductTagRepository } from "../repositories/product-tag" import { FindConfig, Selector } from "../types/common" @@ -33,7 +33,7 @@ class ProductTagService extends TransactionBaseService { tagId: string, config: FindConfig = {} ): Promise { - const tagRepo = this.manager_.getCustomRepository(this.tagRepo_) + const tagRepo = this.manager_.withRepository(this.tagRepo_) const query = buildQuery({ id: tagId }, config) const tag = await tagRepo.findOne(query) @@ -55,7 +55,7 @@ class ProductTagService extends TransactionBaseService { */ async create(tag: Partial): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const tagRepo = manager.getCustomRepository(this.tagRepo_) + const tagRepo = manager.withRepository(this.tagRepo_) const productTag = tagRepo.create(tag) return await tagRepo.save(productTag) @@ -92,7 +92,7 @@ class ProductTagService extends TransactionBaseService { } = {}, config: FindConfig = { skip: 0, take: 20 } ): Promise<[ProductTag[], number]> { - const tagRepo = this.manager_.getCustomRepository(this.tagRepo_) + const tagRepo = this.manager_.withRepository(this.tagRepo_) let q: string | undefined if (isString(selector.q)) { @@ -100,15 +100,21 @@ class ProductTagService extends TransactionBaseService { delete selector.q } + let discount_condition_id + if (selector.discount_condition_id) { + discount_condition_id = selector.discount_condition_id + delete selector.discount_condition_id + } + const query = buildQuery(selector, config) + query.where = query.where as FindOptionsWhere if (q) { query.where.value = ILike(`%${q}%`) } - if (query.where.discount_condition_id) { - const discountConditionId = query.where.discount_condition_id as string - delete query.where.discount_condition_id + if (discount_condition_id) { + const discountConditionId = discount_condition_id as string return await tagRepo.findAndCountByDiscountConditionId( discountConditionId, query diff --git a/packages/medusa/src/services/product-tax-rate.ts b/packages/medusa/src/services/product-tax-rate.ts index 170cec2688..791efbef80 100644 --- a/packages/medusa/src/services/product-tax-rate.ts +++ b/packages/medusa/src/services/product-tax-rate.ts @@ -28,7 +28,7 @@ class ProductTaxRateService extends TransactionBaseService { selector: FilterableProductTaxRateProps, config: FindConfig = { relations: [], skip: 0, take: 20 } ): Promise { - const pTaxRateRepo = this.manager_.getCustomRepository( + const pTaxRateRepo = this.manager_.withRepository( this.productTaxRateRepository_ ) diff --git a/packages/medusa/src/services/product-type.ts b/packages/medusa/src/services/product-type.ts index 618042a491..f42718496e 100644 --- a/packages/medusa/src/services/product-type.ts +++ b/packages/medusa/src/services/product-type.ts @@ -1,8 +1,8 @@ import { MedusaError } from "medusa-core-utils" -import { EntityManager, ILike } from "typeorm" +import { EntityManager, FindOptionsWhere, ILike } from "typeorm" import { ProductType } from "../models" import { ProductTypeRepository } from "../repositories/product-type" -import { FindConfig, Selector } from "../types/common" +import { ExtendedFindConfig, FindConfig, Selector } from "../types/common" import { TransactionBaseService } from "../interfaces" import { buildQuery, isString } from "../utils" @@ -31,7 +31,7 @@ class ProductTypeService extends TransactionBaseService { id: string, config: FindConfig = {} ): Promise { - const typeRepo = this.manager_.getCustomRepository(this.typeRepository_) + const typeRepo = this.manager_.withRepository(this.typeRepository_) const query = buildQuery({ id }, config) const type = await typeRepo.findOne(query) @@ -76,7 +76,7 @@ class ProductTypeService extends TransactionBaseService { } = {}, config: FindConfig = { skip: 0, take: 20 } ): Promise<[ProductType[], number]> { - const typeRepo = this.manager_.getCustomRepository(this.typeRepository_) + const typeRepo = this.manager_.withRepository(this.typeRepository_) let q if (isString(selector.q)) { @@ -84,7 +84,12 @@ class ProductTypeService extends TransactionBaseService { delete selector.q } - const query = buildQuery(selector, config) + const query = buildQuery( + selector, + config + ) as ExtendedFindConfig & { + where: FindOptionsWhere & { discount_condition_id?: string } + } if (q) { query.where.value = ILike(`%${q}%`) diff --git a/packages/medusa/src/services/product-variant.ts b/packages/medusa/src/services/product-variant.ts index 0c2e0140c2..f0c1524993 100644 --- a/packages/medusa/src/services/product-variant.ts +++ b/packages/medusa/src/services/product-variant.ts @@ -1,5 +1,15 @@ import { isDefined, MedusaError } from "medusa-core-utils" -import { Brackets, EntityManager, ILike, SelectQueryBuilder } from "typeorm" +import { + Brackets, + EntityManager, + FindManyOptions, + FindOneOptions, + FindOptionsSelect, + FindOptionsWhere, + ILike, + IsNull, + SelectQueryBuilder, +} from "typeorm" import { IPriceSelectionStrategy, PriceSelectionContext, @@ -27,7 +37,7 @@ import { ProductVariantPrice, UpdateProductVariantInput, } from "../types/product-variant" -import { buildQuery, setMetadata } from "../utils" +import { buildQuery, buildRelations, setMetadata } from "../utils" import EventBusService from "./event-bus" import RegionService from "./region" @@ -88,10 +98,10 @@ class ProductVariantService extends TransactionBaseService { include_discount_prices: false, } ): Promise { - const variantRepo = this.manager_.getCustomRepository( + const variantRepo = this.manager_.withRepository( this.productVariantRepository_ ) - const query = buildQuery({ id: variantId }, config) + const query = buildQuery({ id: variantId }, config) as FindOneOptions const variant = await variantRepo.findOne(query) if (!variant) { @@ -116,7 +126,7 @@ class ProductVariantService extends TransactionBaseService { include_discount_prices: false, } ): Promise { - const variantRepo = this.manager_.getCustomRepository( + const variantRepo = this.manager_.withRepository( this.productVariantRepository_ ) @@ -126,7 +136,7 @@ class ProductVariantService extends TransactionBaseService { config.relations.splice(priceIndex, 1) } - const query = buildQuery({ sku }, config) + const query = buildQuery({ sku }, config) as FindOneOptions const variant = await variantRepo.findOne(query) if (!variant) { @@ -151,10 +161,8 @@ class ProductVariantService extends TransactionBaseService { variant: CreateProductVariantInput ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const productRepo = manager.getCustomRepository(this.productRepository_) - const variantRepo = manager.getCustomRepository( - this.productVariantRepository_ - ) + const productRepo = manager.withRepository(this.productRepository_) + const variantRepo = manager.withRepository(this.productVariantRepository_) const { prices, ...rest } = variant @@ -162,8 +170,12 @@ class ProductVariantService extends TransactionBaseService { if (typeof product === `string`) { product = (await productRepo.findOne({ - where: { id: productOrProductId }, - relations: ["variants", "variants.options", "options"], + where: { id: productOrProductId as string }, + relations: buildRelations([ + "variants", + "variants.options", + "options", + ]), })) as Product } else if (!product.id) { throw new MedusaError( @@ -259,9 +271,7 @@ class ProductVariantService extends TransactionBaseService { update: UpdateProductVariantInput ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const variantRepo = manager.getCustomRepository( - this.productVariantRepository_ - ) + const variantRepo = manager.withRepository(this.productVariantRepository_) let variant = variantOrVariantId if (typeof variant === `string`) { @@ -337,7 +347,7 @@ class ProductVariantService extends TransactionBaseService { prices: ProductVariantPrice[] ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.getCustomRepository( + const moneyAmountRepo = manager.withRepository( this.moneyAmountRepository_ ) @@ -404,7 +414,7 @@ class ProductVariantService extends TransactionBaseService { price: ProductVariantPrice ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.getCustomRepository( + const moneyAmountRepo = manager.withRepository( this.moneyAmountRepository_ ) @@ -412,7 +422,7 @@ class ProductVariantService extends TransactionBaseService { where: { variant_id: variantId, region_id: price.region_id, - price_list_id: null, + price_list_id: IsNull(), }, }) @@ -440,7 +450,7 @@ class ProductVariantService extends TransactionBaseService { price: ProductVariantPrice ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const moneyAmountRepo = manager.getCustomRepository( + const moneyAmountRepo = manager.withRepository( this.moneyAmountRepository_ ) @@ -462,7 +472,7 @@ class ProductVariantService extends TransactionBaseService { optionValue: string ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const productOptionValueRepo = manager.getCustomRepository( + const productOptionValueRepo = manager.withRepository( this.productOptionValueRepository_ ) @@ -500,7 +510,7 @@ class ProductVariantService extends TransactionBaseService { optionValue: string ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const productOptionValueRepo = manager.getCustomRepository( + const productOptionValueRepo = manager.withRepository( this.productOptionValueRepository_ ) @@ -523,8 +533,9 @@ class ProductVariantService extends TransactionBaseService { */ async deleteOptionValue(variantId: string, optionId: string): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const productOptionValueRepo: ProductOptionValueRepository = - manager.getCustomRepository(this.productOptionValueRepository_) + const productOptionValueRepo = manager.withRepository( + this.productOptionValueRepository_ + ) const productOptionValue = await productOptionValueRepo.findOne({ where: { @@ -557,31 +568,51 @@ class ProductVariantService extends TransactionBaseService { include_discount_prices: false, } ): Promise<[ProductVariant[], number]> { - const variantRepo = this.manager_.getCustomRepository( + const variantRepo = this.manager_.withRepository( this.productVariantRepository_ ) - const { q, query, relations } = this.prepareListQuery_(selector, config) - - if (q) { - const qb = this.getFreeTextQueryBuilder_(variantRepo, query, q) - const [raw, count] = await qb.getManyAndCount() - - const variants = await variantRepo.findWithRelations( - relations, - raw.map((i) => i.id), - query.withDeleted ?? false - ) - - return [variants, count] + let q + if (isDefined(selector.q)) { + q = selector.q + delete selector.q } - const [variants, count] = await variantRepo.findWithRelationsAndCount( - relations, - query + const query = buildQuery, ProductVariant>( + selector as FindOptionsSelect, + config ) + query.relationLoadStrategy = "query" - return [variants, count] + if (q) { + query.relations = query.relations ?? {} + query.relations["product"] = query.relations["product"] ?? true + + query.where = query.where as FindOptionsWhere + delete query.where?.title + + query.where = query.where ?? {} + query.where = [ + { + ...query.where, + title: ILike(`%${q}%`), + }, + { + ...query.where, + sku: ILike(`%${q}%`), + }, + { + ...query.where, + product: { + ...((query.where.product ?? + {}) as FindOptionsWhere), + title: ILike(`%${q}%`), + }, + }, + ] + } + + return await variantRepo.findAndCount(query) } /** @@ -597,7 +628,7 @@ class ProductVariantService extends TransactionBaseService { take: 20, } ): Promise { - const productVariantRepo = this.manager_.getCustomRepository( + const productVariantRepo = this.manager_.withRepository( this.productVariantRepository_ ) @@ -613,20 +644,16 @@ class ProductVariantService extends TransactionBaseService { delete selector.q } - const query = buildQuery(selector, config) + const query = buildQuery(selector, config) as FindManyOptions if (q) { - const where = query.where + const where = query.where as FindOptionsWhere - delete where.sku - delete where.title + delete where?.sku + delete where?.title - query.join = { - alias: "variant", - innerJoin: { - product: "variant.product", - }, - } + query.relations = query.relations || {} + query.relations["product"] = true query.where = (qb: SelectQueryBuilder): void => { qb.where(where).andWhere([ @@ -649,9 +676,7 @@ class ProductVariantService extends TransactionBaseService { */ async delete(variantId: string): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const variantRepo = manager.getCustomRepository( - this.productVariantRepository_ - ) + const variantRepo = manager.withRepository(this.productVariantRepository_) const variant = await variantRepo.findOne({ where: { id: variantId }, @@ -696,43 +721,6 @@ class ProductVariantService extends TransactionBaseService { return productsSalesChannels.some((id) => salesChannelIds.includes(id)) } - /** - * Creates a query object to be used for list queries. - * @param selector - the selector to create the query from - * @param config - the config to use for the query - * @return an object containing the query, relations and free-text - * search param. - */ - prepareListQuery_( - selector: FilterableProductVariantProps, - config: FindConfig - ): { query: FindWithRelationsOptions; relations: string[]; q?: string } { - let q: string | undefined - if (isDefined(selector.q)) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (config.relations && config.relations.length > 0) { - query.relations = config.relations - } - - if (config.select && config.select.length > 0) { - query.select = config.select - } - - const rels = query.relations as string[] - delete query.relations - - return { - query, - relations: rels, - q, - } - } - /** * Lists variants based on the provided parameters and includes the count of * variants that match the query. @@ -743,7 +731,7 @@ class ProductVariantService extends TransactionBaseService { * count of products that matches the query as the second element. */ getFreeTextQueryBuilder_( - variantRepo: ProductVariantRepository, + variantRepo: typeof ProductVariantRepository, query: FindWithRelationsOptions, q?: string ): SelectQueryBuilder { diff --git a/packages/medusa/src/services/product.ts b/packages/medusa/src/services/product.ts index 15afb58055..0f868620bd 100644 --- a/packages/medusa/src/services/product.ts +++ b/packages/medusa/src/services/product.ts @@ -15,20 +15,17 @@ import { SalesChannel, } from "../models" import { ImageRepository } from "../repositories/image" -import { - FindWithoutRelationsOptions, - ProductRepository, -} from "../repositories/product" +import { ProductRepository } from "../repositories/product" import { ProductCategoryRepository } from "../repositories/product-category" import { ProductOptionRepository } from "../repositories/product-option" import { ProductTagRepository } from "../repositories/product-tag" import { ProductTypeRepository } from "../repositories/product-type" import { ProductVariantRepository } from "../repositories/product-variant" -import { Selector } from "../types/common" +import { ExtendedFindConfig, FindConfig, Selector } from "../types/common" import { CreateProductInput, - FilterableProductProps, FindProductConfig, + ProductFilterOptions, ProductOptionInput, ProductSelector, UpdateProductInput, @@ -148,19 +145,14 @@ class ProductService extends TransactionBaseService { } ): Promise<[Product[], number]> { const manager = this.manager_ - const productRepo = manager.getCustomRepository(this.productRepository_) + const productRepo = manager.withRepository(this.productRepository_) - const { q, query, relations } = this.prepareListQuery_(selector, config) + const { q, ...productSelector } = selector + const query = buildQuery(productSelector, config) as ExtendedFindConfig< + Product & ProductFilterOptions + > - if (q) { - return await productRepo.getFreeTextSearchResultsAndCount( - q, - query, - relations - ) - } - - return await productRepo.findWithRelationsAndCount(relations, query) + return await productRepo.findAndCount(query, q) } /** @@ -170,7 +162,7 @@ class ProductService extends TransactionBaseService { */ async count(selector: Selector = {}): Promise { const manager = this.manager_ - const productRepo = manager.getCustomRepository(this.productRepository_) + const productRepo = manager.withRepository(this.productRepository_) const query = buildQuery(selector) return await productRepo.count(query) } @@ -252,18 +244,13 @@ class ProductService extends TransactionBaseService { async retrieve_( selector: Selector, config: FindProductConfig = { - include_discount_prices: false, + include_discount_prices: false, // TODO: this seams to be unused from the repository } ): Promise { - const manager = this.manager_ - const productRepo = manager.getCustomRepository(this.productRepository_) - - const { relations, ...query } = buildQuery(selector, config) - - const product = await productRepo.findOneWithRelations( - relations, - query as FindWithoutRelationsOptions - ) + const manager = this.transactionManager_ ?? this.manager_ + const productRepo = manager.withRepository(this.productRepository_) + const query = buildQuery(selector, config as FindConfig) + const product = await productRepo.findOne(query) if (!product) { const selectorConstraints = Object.entries(selector) @@ -336,7 +323,7 @@ class ProductService extends TransactionBaseService { async listTypes(): Promise { const manager = this.manager_ - const productTypeRepository = manager.getCustomRepository( + const productTypeRepository = manager.withRepository( this.productTypeRepository_ ) @@ -345,9 +332,7 @@ class ProductService extends TransactionBaseService { async listTagsByUsage(count = 10): Promise { const manager = this.manager_ - const productTagRepo = manager.getCustomRepository( - this.productTagRepository_ - ) + const productTagRepo = manager.withRepository(this.productTagRepository_) return await productTagRepo.listTagsByUsage(count) } @@ -382,17 +367,13 @@ class ProductService extends TransactionBaseService { */ async create(productObject: CreateProductInput): Promise { return await this.atomicPhase_(async (manager) => { - const productRepo = manager.getCustomRepository(this.productRepository_) - const productTagRepo = manager.getCustomRepository( - this.productTagRepository_ - ) - const productTypeRepo = manager.getCustomRepository( + const productRepo = manager.withRepository(this.productRepository_) + const productTagRepo = manager.withRepository(this.productTagRepository_) + const productTypeRepo = manager.withRepository( this.productTypeRepository_ ) - const imageRepo = manager.getCustomRepository(this.imageRepository_) - const optionRepo = manager.getCustomRepository( - this.productOptionRepository_ - ) + const imageRepo = manager.withRepository(this.imageRepository_) + const optionRepo = manager.withRepository(this.productOptionRepository_) const { options, @@ -494,17 +475,15 @@ class ProductService extends TransactionBaseService { update: UpdateProductInput ): Promise { return await this.atomicPhase_(async (manager) => { - const productRepo = manager.getCustomRepository(this.productRepository_) - const productVariantRepo = manager.getCustomRepository( + const productRepo = manager.withRepository(this.productRepository_) + const productVariantRepo = manager.withRepository( this.productVariantRepository_ ) - const productTagRepo = manager.getCustomRepository( - this.productTagRepository_ - ) - const productTypeRepo = manager.getCustomRepository( + const productTagRepo = manager.withRepository(this.productTagRepository_) + const productTypeRepo = manager.withRepository( this.productTypeRepository_ ) - const imageRepo = manager.getCustomRepository(this.imageRepository_) + const imageRepo = manager.withRepository(this.imageRepository_) const relations = ["tags", "images"] @@ -611,13 +590,18 @@ class ProductService extends TransactionBaseService { */ async delete(productId: string): Promise { return await this.atomicPhase_(async (manager) => { - const productRepo = manager.getCustomRepository(this.productRepository_) + const productRepo = manager.withRepository(this.productRepository_) // Should not fail, if product does not exist, since delete is idempotent - const product = await productRepo.findOne( - { id: productId }, - { relations: ["variants", "variants.prices", "variants.options"] } - ) + const product = await productRepo.findOne({ + where: { id: productId }, + relations: { + variants: { + prices: true, + options: true, + }, + }, + }) if (!product) { return @@ -645,7 +629,7 @@ class ProductService extends TransactionBaseService { */ async addOption(productId: string, optionTitle: string): Promise { return await this.atomicPhase_(async (manager) => { - const productOptionRepo = manager.getCustomRepository( + const productOptionRepo = manager.withRepository( this.productOptionRepository_ ) @@ -691,7 +675,7 @@ class ProductService extends TransactionBaseService { variantOrder: string[] ): Promise { return await this.atomicPhase_(async (manager) => { - const productRepo = manager.getCustomRepository(this.productRepository_) + const productRepo = manager.withRepository(this.productRepository_) const product = await this.retrieve(productId, { relations: ["variants"], @@ -738,7 +722,7 @@ class ProductService extends TransactionBaseService { data: ProductOptionInput ): Promise { return await this.atomicPhase_(async (manager) => { - const productOptionRepo = manager.getCustomRepository( + const productOptionRepo = manager.withRepository( this.productOptionRepository_ ) @@ -792,8 +776,8 @@ class ProductService extends TransactionBaseService { async retrieveOptionByTitle( title: string, productId: string - ): Promise { - const productOptionRepo = this.manager_.getCustomRepository( + ): Promise { + const productOptionRepo = this.manager_.withRepository( this.productOptionRepository_ ) @@ -813,7 +797,7 @@ class ProductService extends TransactionBaseService { optionId: string ): Promise { return await this.atomicPhase_(async (manager) => { - const productOptionRepo = manager.getCustomRepository( + const productOptionRepo = manager.withRepository( this.productOptionRepository_ ) @@ -884,7 +868,7 @@ class ProductService extends TransactionBaseService { profileId: string ): Promise { return await this.atomicPhase_(async (manager) => { - const productRepo = manager.getCustomRepository(this.productRepository_) + const productRepo = manager.withRepository(this.productRepository_) const ids = isString(productIds) ? [productIds] : productIds @@ -897,47 +881,6 @@ class ProductService extends TransactionBaseService { return products }) } - - /** - * Creates a query object to be used for list queries. - * @param selector - the selector to create the query from - * @param config - the config to use for the query - * @return an object containing the query, relations and free-text - * search param. - */ - protected prepareListQuery_( - selector: FilterableProductProps | Selector, - config: FindProductConfig - ): { - q: string - relations: (keyof Product)[] - query: FindWithoutRelationsOptions - } { - let q - if ("q" in selector) { - q = selector.q - delete selector.q - } - - const query = buildQuery(selector, config) - - if (config.relations && config.relations.length > 0) { - query.relations = config.relations - } - - if (config.select && config.select.length > 0) { - query.select = config.select - } - - const rels = query.relations - delete query.relations - - return { - query: query as FindWithoutRelationsOptions, - relations: rels as (keyof Product)[], - q, - } - } } export default ProductService diff --git a/packages/medusa/src/services/publishable-api-key.ts b/packages/medusa/src/services/publishable-api-key.ts index f0ac4d7dd3..50363ba699 100644 --- a/packages/medusa/src/services/publishable-api-key.ts +++ b/packages/medusa/src/services/publishable-api-key.ts @@ -1,4 +1,4 @@ -import { EntityManager, ILike } from "typeorm" +import { EntityManager, FindOptionsWhere, ILike } from "typeorm" import { isDefined, MedusaError } from "medusa-core-utils" import { PublishableApiKeyRepository } from "../repositories/publishable-api-key" @@ -18,6 +18,7 @@ type InjectedDependencies = { eventBusService: EventBusService publishableApiKeyRepository: typeof PublishableApiKeyRepository + // eslint-disable-next-line max-len publishableApiKeySalesChannelRepository: typeof PublishableApiKeySalesChannelRepository } @@ -34,7 +35,9 @@ class PublishableApiKeyService extends TransactionBaseService { protected transactionManager_: EntityManager | undefined protected readonly eventBusService_: EventBusService + // eslint-disable-next-line max-len protected readonly publishableApiKeyRepository_: typeof PublishableApiKeyRepository + // eslint-disable-next-line max-len protected readonly publishableApiKeySalesChannelRepository_: typeof PublishableApiKeySalesChannelRepository constructor({ @@ -65,7 +68,7 @@ class PublishableApiKeyService extends TransactionBaseService { } ): Promise { return await this.atomicPhase_(async (manager) => { - const publishableApiKeyRepo = manager.getCustomRepository( + const publishableApiKeyRepo = manager.withRepository( this.publishableApiKeyRepository_ ) @@ -114,15 +117,12 @@ class PublishableApiKeyService extends TransactionBaseService { selector: Selector, config: FindConfig = {} ): Promise { - const repo = this.manager_.getCustomRepository( - this.publishableApiKeyRepository_ - ) + const repo = this.manager_.withRepository(this.publishableApiKeyRepository_) - const { relations, ...query } = buildQuery(selector, config) - const publishableApiKey = await repo.findOneWithRelations( - relations as (keyof PublishableApiKey)[], - query - ) + const query = buildQuery(selector, config) + query.relationLoadStrategy = "query" + + const publishableApiKey = await repo.findOne(query) if (!publishableApiKey) { const selectorConstraints = Object.entries(selector) @@ -151,9 +151,7 @@ class PublishableApiKeyService extends TransactionBaseService { } ): Promise<[PublishableApiKey[], number]> { const manager = this.manager_ - const pubKeyRepo = manager.getCustomRepository( - this.publishableApiKeyRepository_ - ) + const pubKeyRepo = manager.withRepository(this.publishableApiKeyRepository_) let q if (isString(selector.q)) { @@ -162,6 +160,7 @@ class PublishableApiKeyService extends TransactionBaseService { } const query = buildQuery(selector, config) + query.where = query.where as FindOptionsWhere if (q) { query.where.title = ILike(`%${q}%`) @@ -176,7 +175,7 @@ class PublishableApiKeyService extends TransactionBaseService { ): Promise { { return await this.atomicPhase_(async (manager) => { - const publishableApiKeyRepository = manager.getCustomRepository( + const publishableApiKeyRepository = manager.withRepository( this.publishableApiKeyRepository_ ) @@ -200,9 +199,7 @@ class PublishableApiKeyService extends TransactionBaseService { */ async delete(publishableApiKeyId: string): Promise { return await this.atomicPhase_(async (manager) => { - const repo = manager.getCustomRepository( - this.publishableApiKeyRepository_ - ) + const repo = manager.withRepository(this.publishableApiKeyRepository_) const publishableApiKey = await this.retrieve(publishableApiKeyId).catch() @@ -225,9 +222,7 @@ class PublishableApiKeyService extends TransactionBaseService { } ): Promise { return await this.atomicPhase_(async (manager) => { - const repo = manager.getCustomRepository( - this.publishableApiKeyRepository_ - ) + const repo = manager.withRepository(this.publishableApiKeyRepository_) const pubKey = await this.retrieve(publishableApiKeyId) @@ -272,7 +267,7 @@ class PublishableApiKeyService extends TransactionBaseService { salesChannelIds: string[] ): Promise { return await this.atomicPhase_(async (transactionManager) => { - const pubKeySalesChannelRepo = transactionManager.getCustomRepository( + const pubKeySalesChannelRepo = transactionManager.withRepository( this.publishableApiKeySalesChannelRepository_ ) @@ -294,7 +289,7 @@ class PublishableApiKeyService extends TransactionBaseService { salesChannelIds: string[] ): Promise { return await this.atomicPhase_(async (transactionManager) => { - const pubKeySalesChannelRepo = transactionManager.getCustomRepository( + const pubKeySalesChannelRepo = transactionManager.withRepository( this.publishableApiKeySalesChannelRepository_ ) @@ -316,7 +311,7 @@ class PublishableApiKeyService extends TransactionBaseService { config?: { q?: string } ): Promise { const manager = this.manager_ - const pubKeySalesChannelRepo = manager.getCustomRepository( + const pubKeySalesChannelRepo = manager.withRepository( this.publishableApiKeySalesChannelRepository_ ) @@ -335,7 +330,7 @@ class PublishableApiKeyService extends TransactionBaseService { publishableApiKeyId: string ): Promise<{ sales_channel_id: string[] }> { const manager = this.manager_ - const pubKeySalesChannelRepo = manager.getCustomRepository( + const pubKeySalesChannelRepo = manager.withRepository( this.publishableApiKeySalesChannelRepository_ ) diff --git a/packages/medusa/src/services/region.ts b/packages/medusa/src/services/region.ts index 40aad7c70d..e8f26a9e91 100644 --- a/packages/medusa/src/services/region.ts +++ b/packages/medusa/src/services/region.ts @@ -116,10 +116,8 @@ class RegionService extends TransactionBaseService { */ async create(data: CreateRegionInput): Promise { return await this.atomicPhase_(async (manager) => { - const regionRepository = manager.getCustomRepository( - this.regionRepository_ - ) - const currencyRepository = manager.getCustomRepository( + const regionRepository = manager.withRepository(this.regionRepository_) + const currencyRepository = manager.withRepository( this.currencyRepository_ ) @@ -189,10 +187,8 @@ class RegionService extends TransactionBaseService { */ async update(regionId: string, update: UpdateRegionInput): Promise { return await this.atomicPhase_(async (manager) => { - const regionRepository = manager.getCustomRepository( - this.regionRepository_ - ) - const currencyRepository = manager.getCustomRepository( + const regionRepository = manager.withRepository(this.regionRepository_) + const currencyRepository = manager.withRepository( this.currencyRepository_ ) @@ -264,13 +260,13 @@ class RegionService extends TransactionBaseService { regionData: Omit, id?: T extends UpdateRegionInput ? string : undefined ): Promise> { - const ppRepository = this.manager_.getCustomRepository( + const ppRepository = this.manager_.withRepository( this.paymentProviderRepository_ ) - const fpRepository = this.manager_.getCustomRepository( + const fpRepository = this.manager_.withRepository( this.fulfillmentProviderRepository_ ) - const tpRepository = this.manager_.getCustomRepository( + const tpRepository = this.manager_.withRepository( this.taxProviderRepository_ ) @@ -292,7 +288,7 @@ class RegionService extends TransactionBaseService { if ((regionData as UpdateRegionInput).tax_provider_id) { const tp = await tpRepository.findOne({ - where: { id: (regionData as UpdateRegionInput).tax_provider_id }, + where: { id: (regionData as UpdateRegionInput).tax_provider_id! }, }) if (!tp) { throw new MedusaError( @@ -389,7 +385,7 @@ class RegionService extends TransactionBaseService { code: Country["iso_2"], regionId: string ): Promise { - const countryRepository = this.manager_.getCustomRepository( + const countryRepository = this.manager_.withRepository( this.countryRepository_ ) @@ -438,15 +434,12 @@ class RegionService extends TransactionBaseService { code: Country["iso_2"], config: FindConfig = {} ): Promise { - const countryRepository = this.manager_.getCustomRepository( + const countryRepository = this.manager_.withRepository( this.countryRepository_ ) - const country = await countryRepository.findOne({ - where: { - iso_2: code.toLowerCase(), - }, - }) + const query = buildQuery({ code }, {}) + const country = await countryRepository.findOne(query) if (!country) { throw new MedusaError( @@ -502,7 +495,7 @@ class RegionService extends TransactionBaseService { ) } - const regionRepository = this.manager_.getCustomRepository( + const regionRepository = this.manager_.withRepository( this.regionRepository_ ) @@ -534,7 +527,7 @@ class RegionService extends TransactionBaseService { take: 10, } ): Promise { - const regionRepo = this.manager_.getCustomRepository(this.regionRepository_) + const regionRepo = this.manager_.withRepository(this.regionRepository_) const query = buildQuery(selector, config) return regionRepo.find(query) @@ -548,8 +541,8 @@ class RegionService extends TransactionBaseService { */ async delete(regionId: string): Promise { return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.getCustomRepository(this.regionRepository_) - const countryRepo = manager.getCustomRepository(this.countryRepository_) + const regionRepo = manager.withRepository(this.regionRepository_) + const countryRepo = manager.withRepository(this.countryRepository_) const region = await this.retrieve(regionId, { relations: ["countries"] }) @@ -579,7 +572,7 @@ class RegionService extends TransactionBaseService { */ async addCountry(regionId: string, code: Country["iso_2"]): Promise { return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.getCustomRepository(this.regionRepository_) + const regionRepo = manager.withRepository(this.regionRepository_) const country = await this.validateCountry(code, regionId) @@ -620,7 +613,7 @@ class RegionService extends TransactionBaseService { code: Country["iso_2"] ): Promise { return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.getCustomRepository(this.regionRepository_) + const regionRepo = manager.withRepository(this.regionRepository_) const region = await this.retrieve(regionId, { relations: ["countries"] }) @@ -661,10 +654,8 @@ class RegionService extends TransactionBaseService { providerId: string ): Promise { return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.getCustomRepository(this.regionRepository_) - const ppRepo = manager.getCustomRepository( - this.paymentProviderRepository_ - ) + const regionRepo = manager.withRepository(this.regionRepository_) + const ppRepo = manager.withRepository(this.paymentProviderRepository_) const region = await this.retrieve(regionId, { relations: ["payment_providers"], @@ -712,10 +703,8 @@ class RegionService extends TransactionBaseService { providerId: string ): Promise { return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.getCustomRepository(this.regionRepository_) - const fpRepo = manager.getCustomRepository( - this.fulfillmentProviderRepository_ - ) + const regionRepo = manager.withRepository(this.regionRepository_) + const fpRepo = manager.withRepository(this.fulfillmentProviderRepository_) const region = await this.retrieve(regionId, { relations: ["fulfillment_providers"], @@ -761,7 +750,7 @@ class RegionService extends TransactionBaseService { providerId: string ): Promise { return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.getCustomRepository(this.regionRepository_) + const regionRepo = manager.withRepository(this.regionRepository_) const region = await this.retrieve(regionId, { relations: ["payment_providers"], @@ -800,7 +789,7 @@ class RegionService extends TransactionBaseService { providerId: string ): Promise { return await this.atomicPhase_(async (manager) => { - const regionRepo = manager.getCustomRepository(this.regionRepository_) + const regionRepo = manager.withRepository(this.regionRepository_) const region = await this.retrieve(regionId, { relations: ["fulfillment_providers"], diff --git a/packages/medusa/src/services/return-reason.ts b/packages/medusa/src/services/return-reason.ts index a00e9c904c..495e6c6d42 100644 --- a/packages/medusa/src/services/return-reason.ts +++ b/packages/medusa/src/services/return-reason.ts @@ -28,7 +28,7 @@ class ReturnReasonService extends TransactionBaseService { async create(data: CreateReturnReason): Promise { return await this.atomicPhase_(async (manager) => { - const rrRepo = manager.getCustomRepository(this.retReasonRepo_) + const rrRepo = manager.withRepository(this.retReasonRepo_) if (data.parent_return_reason_id && data.parent_return_reason_id !== "") { const parentReason = await this.retrieve(data.parent_return_reason_id) @@ -49,7 +49,7 @@ class ReturnReasonService extends TransactionBaseService { async update(id: string, data: UpdateReturnReason): Promise { return await this.atomicPhase_(async (manager) => { - const rrRepo = manager.getCustomRepository(this.retReasonRepo_) + const rrRepo = manager.withRepository(this.retReasonRepo_) const reason = await this.retrieve(id) for (const key of Object.keys(data).filter( @@ -77,7 +77,7 @@ class ReturnReasonService extends TransactionBaseService { order: { created_at: "DESC" }, } ): Promise { - const rrRepo = this.manager_.getCustomRepository(this.retReasonRepo_) + const rrRepo = this.manager_.withRepository(this.retReasonRepo_) const query = buildQuery(selector, config) return rrRepo.find(query) } @@ -99,7 +99,7 @@ class ReturnReasonService extends TransactionBaseService { ) } - const rrRepo = this.manager_.getCustomRepository(this.retReasonRepo_) + const rrRepo = this.manager_.withRepository(this.retReasonRepo_) const query = buildQuery({ id: returnReasonId }, config) const item = await rrRepo.findOne(query) @@ -116,7 +116,7 @@ class ReturnReasonService extends TransactionBaseService { async delete(returnReasonId: string): Promise { return this.atomicPhase_(async (manager) => { - const rrRepo = manager.getCustomRepository(this.retReasonRepo_) + const rrRepo = manager.withRepository(this.retReasonRepo_) // We include the relation 'return_reason_children' to enable cascading deletes of return reasons if a parent is removed const reason = await this.retrieve(returnReasonId, { diff --git a/packages/medusa/src/services/return.ts b/packages/medusa/src/services/return.ts index bda67554ef..0c21856b28 100644 --- a/packages/medusa/src/services/return.ts +++ b/packages/medusa/src/services/return.ts @@ -151,7 +151,7 @@ class ReturnService extends TransactionBaseService { order: { created_at: "DESC" }, } ): Promise { - const returnRepo = this.manager_.getCustomRepository(this.returnRepository_) + const returnRepo = this.manager_.withRepository(this.returnRepository_) const query = buildQuery(selector, config) return returnRepo.find(query) } @@ -172,7 +172,7 @@ class ReturnService extends TransactionBaseService { ) } - const retRepo = manager.getCustomRepository(this.returnRepository_) + const retRepo = manager.withRepository(this.returnRepository_) ret.status = ReturnStatus.CANCELED @@ -270,7 +270,7 @@ class ReturnService extends TransactionBaseService { ) } - const returnRepository = this.manager_.getCustomRepository( + const returnRepository = this.manager_.withRepository( this.returnRepository_ ) @@ -291,7 +291,7 @@ class ReturnService extends TransactionBaseService { swapId: string, relations: string[] = [] ): Promise { - const returnRepository = this.manager_.getCustomRepository( + const returnRepository = this.manager_.withRepository( this.returnRepository_ ) @@ -333,7 +333,7 @@ class ReturnService extends TransactionBaseService { ret[key] = value } - const retRepo = manager.getCustomRepository(this.returnRepository_) + const retRepo = manager.withRepository(this.returnRepository_) return await retRepo.save(ret) }) } @@ -348,9 +348,7 @@ class ReturnService extends TransactionBaseService { */ async create(data: CreateReturnInput): Promise { return await this.atomicPhase_(async (manager) => { - const returnRepository = manager.getCustomRepository( - this.returnRepository_ - ) + const returnRepository = manager.withRepository(this.returnRepository_) const orderId = data.order_id if (data.swap_id) { @@ -440,7 +438,7 @@ class ReturnService extends TransactionBaseService { ) } - const rItemRepo = manager.getCustomRepository(this.returnItemRepository_) + const rItemRepo = manager.withRepository(this.returnItemRepository_) returnObject.items = returnLines.map((i) => rItemRepo.create({ item_id: i.id, @@ -543,7 +541,7 @@ class ReturnService extends TransactionBaseService { returnOrder.shipping_data = await this.fulfillmentProviderService_.createReturn(returnData) - const returnRepo = manager.getCustomRepository(this.returnRepository_) + const returnRepo = manager.withRepository(this.returnRepository_) return await returnRepo.save(returnOrder) }) } @@ -571,9 +569,7 @@ class ReturnService extends TransactionBaseService { context: { locationId?: string } = {} ): Promise { return await this.atomicPhase_(async (manager) => { - const returnRepository = manager.getCustomRepository( - this.returnRepository_ - ) + const returnRepository = manager.withRepository(this.returnRepository_) const returnObj = await this.retrieve(returnId, { relations: ["items", "swap", "swap.additional_items"], diff --git a/packages/medusa/src/services/sales-channel.ts b/packages/medusa/src/services/sales-channel.ts index 05eefbfd80..b106ad73a2 100644 --- a/packages/medusa/src/services/sales-channel.ts +++ b/packages/medusa/src/services/sales-channel.ts @@ -66,16 +66,16 @@ class SalesChannelService extends TransactionBaseService { ): Promise { const manager = this.getManager() - const salesChannelRepo = manager.getCustomRepository( + const salesChannelRepo = manager.withRepository( this.salesChannelRepository_ ) - const { relations, ...query } = buildQuery(selector, config) + const query = buildQuery(selector, config) - const salesChannel = await salesChannelRepo.findOneWithRelations( - relations as (keyof SalesChannel)[], - query - ) + const salesChannel = await salesChannelRepo.findOne({ + ...query, + relationLoadStrategy: "query", + }) if (!salesChannel) { const selectorConstraints = Object.entries(selector) @@ -150,7 +150,7 @@ class SalesChannelService extends TransactionBaseService { } ): Promise<[SalesChannel[], number]> { const manager = this.getManager() - const salesChannelRepo = manager.getCustomRepository( + const salesChannelRepo = manager.withRepository( this.salesChannelRepository_ ) @@ -179,8 +179,8 @@ class SalesChannelService extends TransactionBaseService { */ async create(data: CreateSalesChannelInput): Promise { return await this.atomicPhase_(async (manager) => { - const salesChannelRepo: SalesChannelRepository = - manager.getCustomRepository(this.salesChannelRepository_) + const salesChannelRepo: typeof SalesChannelRepository = + manager.withRepository(this.salesChannelRepository_) const salesChannel = salesChannelRepo.create(data) @@ -199,8 +199,8 @@ class SalesChannelService extends TransactionBaseService { data: UpdateSalesChannelInput ): Promise { return await this.atomicPhase_(async (transactionManager) => { - const salesChannelRepo: SalesChannelRepository = - transactionManager.getCustomRepository(this.salesChannelRepository_) + const salesChannelRepo: typeof SalesChannelRepository = + transactionManager.withRepository(this.salesChannelRepository_) const salesChannel = await this.retrieve(salesChannelId) @@ -230,7 +230,7 @@ class SalesChannelService extends TransactionBaseService { */ async delete(salesChannelId: string): Promise { return await this.atomicPhase_(async (transactionManager) => { - const salesChannelRepo = transactionManager.getCustomRepository( + const salesChannelRepo = transactionManager.withRepository( this.salesChannelRepository_ ) @@ -325,7 +325,7 @@ class SalesChannelService extends TransactionBaseService { productIds: string[] ): Promise { return await this.atomicPhase_(async (transactionManager) => { - const salesChannelRepo = transactionManager.getCustomRepository( + const salesChannelRepo = transactionManager.withRepository( this.salesChannelRepository_ ) @@ -346,7 +346,7 @@ class SalesChannelService extends TransactionBaseService { productIds: string[] ): Promise { return await this.atomicPhase_(async (transactionManager) => { - const salesChannelRepo = transactionManager.getCustomRepository( + const salesChannelRepo = transactionManager.withRepository( this.salesChannelRepository_ ) diff --git a/packages/medusa/src/services/shipping-option.ts b/packages/medusa/src/services/shipping-option.ts index c672fb59ef..2d1f735115 100644 --- a/packages/medusa/src/services/shipping-option.ts +++ b/packages/medusa/src/services/shipping-option.ts @@ -13,7 +13,7 @@ import { import { ShippingMethodRepository } from "../repositories/shipping-method" import { ShippingOptionRepository } from "../repositories/shipping-option" import { ShippingOptionRequirementRepository } from "../repositories/shipping-option-requirement" -import { ExtendedFindConfig, FindConfig, Selector } from "../types/common" +import { FindConfig, Selector } from "../types/common" import { CreateShippingMethodDto, CreateShippingOptionInput, @@ -101,16 +101,18 @@ class ShippingOptionService extends TransactionBaseService { ) } - const reqRepo = manager.getCustomRepository(this.requirementRepository_) + const reqRepo = manager.withRepository(this.requirementRepository_) - const existingReq = await reqRepo.findOne({ - where: { id: requirement.id }, - }) + const existingReq = requirement.id + ? await reqRepo.findOne({ + where: { id: requirement.id }, + }) + : undefined if (!existingReq && requirement.id) { throw new MedusaError( MedusaError.Types.INVALID_DATA, - "ID does not exist" + `Shipping option requirement with id ${requirement.id} does not exist` ) } @@ -150,7 +152,7 @@ class ShippingOptionService extends TransactionBaseService { config: FindConfig = { skip: 0, take: 50 } ): Promise { const manager = this.manager_ - const optRepo = manager.getCustomRepository(this.optionRepository_) + const optRepo = manager.withRepository(this.optionRepository_) const query = buildQuery(selector, config) return optRepo.find(query) @@ -166,7 +168,7 @@ class ShippingOptionService extends TransactionBaseService { config: FindConfig = { skip: 0, take: 50 } ): Promise<[ShippingOption[], number]> { const manager = this.manager_ - const optRepo = manager.getCustomRepository(this.optionRepository_) + const optRepo = manager.withRepository(this.optionRepository_) const query = buildQuery(selector, config) return await optRepo.findAndCount(query) @@ -181,7 +183,7 @@ class ShippingOptionService extends TransactionBaseService { */ async retrieve( optionId, - options: { select?: (keyof ShippingOption)[]; relations?: string[] } = {} + options: FindConfig = {} ): Promise { if (!isDefined(optionId)) { throw new MedusaError( @@ -191,21 +193,9 @@ class ShippingOptionService extends TransactionBaseService { } const manager = this.manager_ - const soRepo: ShippingOptionRepository = manager.getCustomRepository( - this.optionRepository_ - ) + const soRepo = manager.withRepository(this.optionRepository_) - const query: ExtendedFindConfig = { - where: { id: optionId }, - } - - if (options.select) { - query.select = options.select - } - - if (options.relations) { - query.relations = options.relations - } + const query = buildQuery({ id: optionId }, options) const option = await soRepo.findOne(query) @@ -231,9 +221,7 @@ class ShippingOptionService extends TransactionBaseService { update: ShippingMethodUpdate ): Promise { return await this.atomicPhase_(async (manager) => { - const methodRepo: ShippingMethodRepository = manager.getCustomRepository( - this.methodRepository_ - ) + const methodRepo = manager.withRepository(this.methodRepository_) const method = await methodRepo.findOne({ where: { id } }) if (!method) { @@ -263,7 +251,7 @@ class ShippingOptionService extends TransactionBaseService { : [shippingMethods] return await this.atomicPhase_(async (manager) => { - const methodRepo = manager.getCustomRepository(this.methodRepository_) + const methodRepo = manager.withRepository(this.methodRepository_) return await methodRepo.remove(removeEntities) }) } @@ -285,7 +273,7 @@ class ShippingOptionService extends TransactionBaseService { relations: ["requirements"], }) - const methodRepo = manager.getCustomRepository(this.methodRepository_) + const methodRepo = manager.withRepository(this.methodRepository_) if (isDefined(config.cart)) { await this.validateCartOption(option, config.cart) @@ -454,7 +442,7 @@ class ShippingOptionService extends TransactionBaseService { price_type: data.price_type, }) - const optionRepo = manager.getCustomRepository(this.optionRepository_) + const optionRepo = manager.withRepository(this.optionRepository_) const option = optionRepo.create(optionWithValidatedPrice) const region = await this.regionService_ @@ -677,7 +665,7 @@ class ShippingOptionService extends TransactionBaseService { } } - const optionRepo = manager.getCustomRepository(this.optionRepository_) + const optionRepo = manager.withRepository(this.optionRepository_) return await optionRepo.save(optionWithValidatedPrice) }) } @@ -693,7 +681,7 @@ class ShippingOptionService extends TransactionBaseService { try { const option = await this.retrieve(optionId) - const optionRepo = manager.getCustomRepository(this.optionRepository_) + const optionRepo = manager.withRepository(this.optionRepository_) return optionRepo.softRemove(option) } catch (error) { @@ -729,7 +717,7 @@ class ShippingOptionService extends TransactionBaseService { option.requirements.push(validatedReq) - const optionRepo = manager.getCustomRepository(this.optionRepository_) + const optionRepo = manager.withRepository(this.optionRepository_) return optionRepo.save(option) }) } @@ -743,14 +731,14 @@ class ShippingOptionService extends TransactionBaseService { requirementId ): Promise { return await this.atomicPhase_(async (manager) => { - const reqRepo: ShippingOptionRequirementRepository = - manager.getCustomRepository(this.requirementRepository_) + const reqRepo = manager.withRepository(this.requirementRepository_) const requirement = await reqRepo.findOne({ where: { id: requirementId }, }) + // Delete is idempotent, but we return a promise to allow then-chaining - if (typeof requirement === "undefined") { + if (!requirement) { return Promise.resolve() } @@ -769,7 +757,7 @@ class ShippingOptionService extends TransactionBaseService { profileId: string ): Promise { return await this.atomicPhase_(async (manager) => { - const optionRepo = manager.getCustomRepository(this.optionRepository_) + const optionRepo = manager.withRepository(this.optionRepository_) const ids = isString(optionIds) ? [optionIds] : optionIds diff --git a/packages/medusa/src/services/shipping-profile.ts b/packages/medusa/src/services/shipping-profile.ts index d427f73e77..e7be3140d0 100644 --- a/packages/medusa/src/services/shipping-profile.ts +++ b/packages/medusa/src/services/shipping-profile.ts @@ -72,11 +72,14 @@ class ShippingProfileService extends TransactionBaseService { selector: Selector = {}, config: FindConfig = { relations: [], skip: 0, take: 10 } ): Promise { - const shippingProfileRepo = this.manager_.getCustomRepository( + const shippingProfileRepo = this.manager_.withRepository( this.shippingProfileRepository_ ) - const query = buildQuery(selector, config) + const query = buildQuery, ShippingProfile>( + selector, + config + ) return shippingProfileRepo.find(query) } @@ -143,7 +146,7 @@ class ShippingProfileService extends TransactionBaseService { ) } - const profileRepository = this.manager_.getCustomRepository( + const profileRepository = this.manager_.withRepository( this.shippingProfileRepository_ ) @@ -161,13 +164,13 @@ class ShippingProfileService extends TransactionBaseService { return profile } - async retrieveDefault(): Promise { - const profileRepository = this.manager_.getCustomRepository( + async retrieveDefault(): Promise { + const profileRepository = this.manager_.withRepository( this.shippingProfileRepository_ ) const profile = await profileRepository.findOne({ - where: { type: "default" }, + where: { type: ShippingProfileType.DEFAULT }, }) return profile @@ -182,7 +185,7 @@ class ShippingProfileService extends TransactionBaseService { let profile = await this.retrieveDefault() if (!profile) { - const profileRepository = manager.getCustomRepository( + const profileRepository = manager.withRepository( this.shippingProfileRepository_ ) @@ -204,13 +207,13 @@ class ShippingProfileService extends TransactionBaseService { * Retrieves the default gift card profile * @return the shipping profile for gift cards */ - async retrieveGiftCardDefault(): Promise { - const profileRepository = this.manager_.getCustomRepository( + async retrieveGiftCardDefault(): Promise { + const profileRepository = this.manager_.withRepository( this.shippingProfileRepository_ ) const giftCardProfile = await profileRepository.findOne({ - where: { type: "gift_card" }, + where: { type: ShippingProfileType.GIFT_CARD }, }) return giftCardProfile @@ -226,7 +229,7 @@ class ShippingProfileService extends TransactionBaseService { let profile = await this.retrieveGiftCardDefault() if (!profile) { - const profileRepository = manager.getCustomRepository( + const profileRepository = manager.withRepository( this.shippingProfileRepository_ ) @@ -249,7 +252,7 @@ class ShippingProfileService extends TransactionBaseService { */ async create(profile: CreateShippingProfile): Promise { return await this.atomicPhase_(async (manager) => { - const profileRepository = manager.getCustomRepository( + const profileRepository = manager.withRepository( this.shippingProfileRepository_ ) @@ -287,7 +290,7 @@ class ShippingProfileService extends TransactionBaseService { update: UpdateShippingProfile ): Promise { return await this.atomicPhase_(async (manager) => { - const profileRepository = manager.getCustomRepository( + const profileRepository = manager.withRepository( this.shippingProfileRepository_ ) @@ -330,7 +333,7 @@ class ShippingProfileService extends TransactionBaseService { */ async delete(profileId: string): Promise { return await this.atomicPhase_(async (manager) => { - const profileRepo = manager.getCustomRepository( + const profileRepo = manager.withRepository( this.shippingProfileRepository_ ) diff --git a/packages/medusa/src/services/shipping-tax-rate.ts b/packages/medusa/src/services/shipping-tax-rate.ts index d7f46cbc2e..b51e730f75 100644 --- a/packages/medusa/src/services/shipping-tax-rate.ts +++ b/packages/medusa/src/services/shipping-tax-rate.ts @@ -10,6 +10,7 @@ class ShippingTaxRateService extends TransactionBaseService { protected manager_: EntityManager protected transactionManager_: EntityManager | undefined + // eslint-disable-next-line max-len protected readonly shippingTaxRateRepository_: typeof ShippingTaxRateRepository constructor({ manager, shippingTaxRateRepository }) { @@ -29,7 +30,7 @@ class ShippingTaxRateService extends TransactionBaseService { selector: FilterableShippingTaxRateProps, config: FindConfig = { relations: [], skip: 0, take: 20 } ): Promise { - const sTaxRateRepo = this.manager_.getCustomRepository( + const sTaxRateRepo = this.manager_.withRepository( this.shippingTaxRateRepository_ ) diff --git a/packages/medusa/src/services/store.ts b/packages/medusa/src/services/store.ts index c4401c9805..361d6abcb8 100644 --- a/packages/medusa/src/services/store.ts +++ b/packages/medusa/src/services/store.ts @@ -1,5 +1,5 @@ import { MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" +import { EntityManager, IsNull, Not } from "typeorm" import { TransactionBaseService } from "../interfaces" import { Currency, Store } from "../models" import { CurrencyRepository } from "../repositories/currency" @@ -49,10 +49,10 @@ class StoreService extends TransactionBaseService { async create(): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const storeRepository = transactionManager.getCustomRepository( + const storeRepository = transactionManager.withRepository( this.storeRepository_ ) - const currencyRepository = transactionManager.getCustomRepository( + const currencyRepository = transactionManager.withRepository( this.currencyRepository_ ) @@ -64,7 +64,9 @@ class StoreService extends TransactionBaseService { const newStore = storeRepository.create() // Add default currency (USD) to store currencies const usd = await currencyRepository.findOne({ - code: "usd", + where: { + code: "usd", + }, }) if (usd) { @@ -84,8 +86,13 @@ class StoreService extends TransactionBaseService { */ async retrieve(config: FindConfig = {}): Promise { const manager = this.manager_ - const storeRepo = manager.getCustomRepository(this.storeRepository_) - const query = buildQuery({}, config) + const storeRepo = manager.withRepository(this.storeRepository_) + const query = buildQuery( + { + id: Not(IsNull()), + }, + config + ) const store = await storeRepo.findOne(query) if (!store) { @@ -114,10 +121,10 @@ class StoreService extends TransactionBaseService { async update(data: UpdateStoreInput): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const storeRepository = transactionManager.getCustomRepository( + const storeRepository = transactionManager.withRepository( this.storeRepository_ ) - const currencyRepository = transactionManager.getCustomRepository( + const currencyRepository = transactionManager.withRepository( this.currencyRepository_ ) @@ -180,7 +187,9 @@ class StoreService extends TransactionBaseService { } const curr = (await currencyRepository.findOne({ - code: default_currency_code.toLowerCase(), + where: { + code: default_currency_code.toLowerCase(), + }, })) as Currency store.default_currency = curr @@ -204,10 +213,10 @@ class StoreService extends TransactionBaseService { async addCurrency(code: string): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const storeRepo = transactionManager.getCustomRepository( + const storeRepo = transactionManager.withRepository( this.storeRepository_ ) - const currencyRepository = transactionManager.getCustomRepository( + const currencyRepository = transactionManager.withRepository( this.currencyRepository_ ) @@ -248,7 +257,7 @@ class StoreService extends TransactionBaseService { async removeCurrency(code: string): Promise { return await this.atomicPhase_( async (transactionManager: EntityManager) => { - const storeRepo = transactionManager.getCustomRepository( + const storeRepo = transactionManager.withRepository( this.storeRepository_ ) const store = await this.retrieve({ relations: ["currencies"] }) diff --git a/packages/medusa/src/services/swap.ts b/packages/medusa/src/services/swap.ts index 54247ffef3..38933e6f2a 100644 --- a/packages/medusa/src/services/swap.ts +++ b/packages/medusa/src/services/swap.ts @@ -219,20 +219,14 @@ class SwapService extends TransactionBaseService { ) } - const swapRepo = this.manager_.getCustomRepository(this.swapRepository_) + const swapRepo = this.manager_.withRepository(this.swapRepository_) const { cartSelects, cartRelations, ...newConfig } = this.transformQueryForCart(config) const query = buildQuery({ id: swapId }, newConfig) - const relations = query.relations as (keyof Swap)[] - delete query.relations - - const swap = await swapRepo.findOneWithRelations( - relations, - query as FindConfig - ) + const swap = await swapRepo.findOne(query) if (!swap) { throw new MedusaError(MedusaError.Types.NOT_FOUND, "Swap was not found") @@ -261,7 +255,7 @@ class SwapService extends TransactionBaseService { cartId: string, relations: FindConfig["relations"] = [] ): Promise { - const swapRepo = this.manager_.getCustomRepository(this.swapRepository_) + const swapRepo = this.manager_.withRepository(this.swapRepository_) const swap = await swapRepo.findOne({ where: { @@ -292,13 +286,11 @@ class SwapService extends TransactionBaseService { order: { created_at: "DESC" }, } ): Promise { - const swapRepo = this.manager_.getCustomRepository(this.swapRepository_) + const swapRepo = this.manager_.withRepository(this.swapRepository_) const query = buildQuery(selector, config) + query.relationLoadStrategy = "query" - const relations = query.relations as (keyof Swap)[] - delete query.relations - - return await swapRepo.findWithRelations(relations, query) + return await swapRepo.find(query) } /** @@ -375,7 +367,7 @@ class SwapService extends TransactionBaseService { const evaluatedNoNotification = no_notification !== undefined ? no_notification : order.no_notification - const swapRepo = manager.getCustomRepository(this.swapRepository_) + const swapRepo = manager.withRepository(this.swapRepository_) const created = swapRepo.create({ ...rest, fulfillment_status: SwapFulfillmentStatus.NOT_FULFILLED, @@ -432,7 +424,7 @@ class SwapService extends TransactionBaseService { ) } - const swapRepo = manager.getCustomRepository(this.swapRepository_) + const swapRepo = manager.withRepository(this.swapRepository_) if (swap.difference_due < 0) { if (swap.payment_status === "difference_refunded") { return swap @@ -553,7 +545,7 @@ class SwapService extends TransactionBaseService { // await this.updateShippingAddress_(swap, update.shipping_address) } - const swapRepo = manager.getCustomRepository(this.swapRepository_) + const swapRepo = manager.withRepository(this.swapRepository_) return await swapRepo.save(swap) }) } @@ -573,12 +565,14 @@ class SwapService extends TransactionBaseService { customShippingOptions: { option_id: string; price: number }[] = [] ): Promise { return await this.atomicPhase_(async (manager) => { - const swapRepo = manager.getCustomRepository(this.swapRepository_) + const swapRepo = manager.withRepository(this.swapRepository_) const swap = await this.retrieve(swapId, { relations: [ "order", "order.items", + "order.items.variant", + "order.items.variant.product", "order.swaps", "order.swaps.additional_items", "order.discounts", @@ -655,7 +649,7 @@ class SwapService extends TransactionBaseService { cart = await this.cartService_ .withTransaction(manager) .retrieve(cart.id, { - relations: ["items", "region", "discounts", "discounts.rule"], + relations: ["items", "items.variant", "region", "discounts", "discounts.rule"], }) await Promise.all( @@ -804,7 +798,7 @@ class SwapService extends TransactionBaseService { swap.payment_status = total === 0 ? SwapPaymentStatus.CONFIRMED : SwapPaymentStatus.AWAITING - const swapRepo = manager.getCustomRepository(this.swapRepository_) + const swapRepo = manager.withRepository(this.swapRepository_) const result = await swapRepo.save(swap) const shippingOptionServiceTx = @@ -841,7 +835,7 @@ class SwapService extends TransactionBaseService { */ async cancel(swapId: string): Promise { return await this.atomicPhase_(async (manager) => { - const swapRepo = manager.getCustomRepository(this.swapRepository_) + const swapRepo = manager.withRepository(this.swapRepository_) const swap = await this.retrieve(swapId, { relations: ["payment", "fulfillments", "return_order"], @@ -910,7 +904,7 @@ class SwapService extends TransactionBaseService { ): Promise { return await this.atomicPhase_(async (manager) => { const { metadata, no_notification } = config - const swapRepo = manager.getCustomRepository(this.swapRepository_) + const swapRepo = manager.withRepository(this.swapRepository_) const swap = await this.retrieve(swapId, { relations: [ @@ -1042,7 +1036,7 @@ class SwapService extends TransactionBaseService { */ async cancelFulfillment(fulfillmentId: string): Promise { return await this.atomicPhase_(async (manager) => { - const swapRepo = manager.getCustomRepository(this.swapRepository_) + const swapRepo = manager.withRepository(this.swapRepository_) const canceled = await this.fulfillmentService_ .withTransaction(manager) .cancelFulfillment(fulfillmentId) @@ -1082,7 +1076,7 @@ class SwapService extends TransactionBaseService { ): Promise { return await this.atomicPhase_(async (manager) => { const { metadata, no_notification } = config - const swapRepo = manager.getCustomRepository(this.swapRepository_) + const swapRepo = manager.withRepository(this.swapRepository_) const swap = await this.retrieve(swapId, { relations: ["additional_items"], @@ -1154,11 +1148,9 @@ class SwapService extends TransactionBaseService { async (transactionManager: EntityManager) => { const validatedId = validateId(swapId) - const swapRepo = transactionManager.getCustomRepository( - this.swapRepository_ - ) + const swapRepo = transactionManager.withRepository(this.swapRepository_) - const swap = await swapRepo.findOne(validatedId) + const swap = await swapRepo.findOne({ where: { id: validatedId } }) if (!swap) { throw new MedusaError( diff --git a/packages/medusa/src/services/tax-provider.ts b/packages/medusa/src/services/tax-provider.ts index 4e7d7b23be..4771bc7f2f 100644 --- a/packages/medusa/src/services/tax-provider.ts +++ b/packages/medusa/src/services/tax-provider.ts @@ -63,7 +63,7 @@ class TaxProviderService extends TransactionBaseService { } async list(): Promise { - const tpRepo = this.manager_.getCustomRepository(this.taxProviderRepo_) + const tpRepo = this.manager_.withRepository(this.taxProviderRepo_) return tpRepo.find({}) } @@ -96,7 +96,7 @@ class TaxProviderService extends TransactionBaseService { async clearLineItemsTaxLines(itemIds: string[]): Promise { return await this.atomicPhase_(async (transactionManager) => { - const taxLineRepo = transactionManager.getCustomRepository( + const taxLineRepo = transactionManager.withRepository( this.taxLineRepo_ ) @@ -106,10 +106,10 @@ class TaxProviderService extends TransactionBaseService { async clearTaxLines(cartId: string): Promise { return await this.atomicPhase_(async (transactionManager) => { - const taxLineRepo = transactionManager.getCustomRepository( + const taxLineRepo = transactionManager.withRepository( this.taxLineRepo_ ) - const shippingTaxRepo = transactionManager.getCustomRepository( + const shippingTaxRepo = transactionManager.withRepository( this.smTaxLineRepo_ ) @@ -141,10 +141,10 @@ class TaxProviderService extends TransactionBaseService { taxLines = await this.getTaxLines(cartOrLineItems, calculationContext) } - const itemTaxLineRepo = transactionManager.getCustomRepository( + const itemTaxLineRepo = transactionManager.withRepository( this.taxLineRepo_ ) - const shippingTaxLineRepo = transactionManager.getCustomRepository( + const shippingTaxLineRepo = transactionManager.withRepository( this.smTaxLineRepo_ ) @@ -222,7 +222,7 @@ class TaxProviderService extends TransactionBaseService { calculationContext ) - const smTaxLineRepo = this.manager_.getCustomRepository(this.smTaxLineRepo_) + const smTaxLineRepo = this.manager_.withRepository(this.smTaxLineRepo_) // .create only creates entities nothing is persisted in DB return providerLines.map((pl) => { @@ -311,8 +311,8 @@ class TaxProviderService extends TransactionBaseService { calculationContext ) - const liTaxLineRepo = this.manager_.getCustomRepository(this.taxLineRepo_) - const smTaxLineRepo = this.manager_.getCustomRepository(this.smTaxLineRepo_) + const liTaxLineRepo = this.manager_.withRepository(this.taxLineRepo_) + const smTaxLineRepo = this.manager_.withRepository(this.smTaxLineRepo_) // .create only creates entities nothing is persisted in DB return providerLines.map((pl) => { @@ -486,7 +486,7 @@ class TaxProviderService extends TransactionBaseService { } async registerInstalledProviders(providers: string[]): Promise { - const model = this.manager_.getCustomRepository(this.taxProviderRepo_) + const model = this.manager_.withRepository(this.taxProviderRepo_) await model.update({}, { is_installed: false }) for (const p of providers) { diff --git a/packages/medusa/src/services/tax-rate.ts b/packages/medusa/src/services/tax-rate.ts index 272b6ab82c..0c9df19059 100644 --- a/packages/medusa/src/services/tax-rate.ts +++ b/packages/medusa/src/services/tax-rate.ts @@ -1,5 +1,5 @@ import { isDefined, MedusaError } from "medusa-core-utils" -import { EntityManager } from "typeorm" +import { EntityManager, In } from "typeorm" import { ProductTaxRate, ProductTypeTaxRate, @@ -19,7 +19,6 @@ import { } from "../types/tax-rate" import { buildQuery, PostgresError } from "../utils" import { TransactionBaseService } from "../interfaces" -import { FindConditions } from "typeorm/find-options/FindConditions" class TaxRateService extends TransactionBaseService { protected manager_: EntityManager @@ -50,9 +49,7 @@ class TaxRateService extends TransactionBaseService { selector: FilterableTaxRateProps, config: FindConfig = {} ): Promise { - const taxRateRepo = this.manager_.getCustomRepository( - this.taxRateRepository_ - ) + const taxRateRepo = this.manager_.withRepository(this.taxRateRepository_) const query = buildQuery(selector, config) return await taxRateRepo.findWithResolution(query) } @@ -61,9 +58,7 @@ class TaxRateService extends TransactionBaseService { selector: FilterableTaxRateProps, config: FindConfig = {} ): Promise<[TaxRate[], number]> { - const taxRateRepo = this.manager_.getCustomRepository( - this.taxRateRepository_ - ) + const taxRateRepo = this.manager_.withRepository(this.taxRateRepository_) const query = buildQuery(selector, config) return await taxRateRepo.findAndCountWithResolution(query) } @@ -80,7 +75,7 @@ class TaxRateService extends TransactionBaseService { } const manager = this.manager_ - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) const query = buildQuery({ id: taxRateId }, config) const taxRate = await taxRateRepo.findOneWithResolution(query) @@ -96,7 +91,7 @@ class TaxRateService extends TransactionBaseService { async create(data: CreateTaxRateInput): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) if (typeof data.region_id === "undefined") { throw new MedusaError( @@ -112,7 +107,7 @@ class TaxRateService extends TransactionBaseService { async update(id: string, data: UpdateTaxRateInput): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) const taxRate = await this.retrieve(id) for (const [k, v] of Object.entries(data)) { @@ -127,9 +122,13 @@ class TaxRateService extends TransactionBaseService { async delete(id: string | string[]): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) const query = buildQuery({ id }) - await taxRateRepo.delete(query.where as FindConditions) + if (Array.isArray(id)) { + await taxRateRepo.delete({ id: In(id) }) + } else { + await taxRateRepo.delete({ id: id }) + } }) } @@ -138,7 +137,7 @@ class TaxRateService extends TransactionBaseService { productIds: string | string[] ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) let ids: string[] if (typeof productIds === "string") { @@ -156,7 +155,7 @@ class TaxRateService extends TransactionBaseService { typeIds: string | string[] ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) let ids: string[] if (typeof typeIds === "string") { @@ -174,7 +173,7 @@ class TaxRateService extends TransactionBaseService { optionIds: string | string[] ): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) let ids: string[] if (typeof optionIds === "string") { @@ -201,7 +200,7 @@ class TaxRateService extends TransactionBaseService { const result = await this.atomicPhase_( async (manager: EntityManager) => { - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) return await taxRateRepo.addToProduct(id, ids, replace) }, // eslint-disable-next-line @@ -237,7 +236,7 @@ class TaxRateService extends TransactionBaseService { return await this.atomicPhase_( async (manager: EntityManager) => { - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) return await taxRateRepo.addToProductType(id, ids, replace) }, // eslint-disable-next-line @@ -277,7 +276,7 @@ class TaxRateService extends TransactionBaseService { return await this.atomicPhase_( async (manager: EntityManager) => { - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) const taxRate = await this.retrieve(id, { select: ["id", "region_id"] }) const options = await this.shippingOptionService_.list( { id: ids }, @@ -317,13 +316,13 @@ class TaxRateService extends TransactionBaseService { ): Promise { // Check both ProductTaxRate + ProductTypeTaxRate const manager = this.manager_ - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) return await taxRateRepo.listByProduct(productId, config) } async listByShippingOption(shippingOptionId: string): Promise { const manager = this.manager_ - const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRateRepo = manager.withRepository(this.taxRateRepository_) return await taxRateRepo.listByShippingOption(shippingOptionId) } } diff --git a/packages/medusa/src/services/user.ts b/packages/medusa/src/services/user.ts index eda257f93a..aade379380 100644 --- a/packages/medusa/src/services/user.ts +++ b/packages/medusa/src/services/user.ts @@ -68,7 +68,7 @@ class UserService extends TransactionBaseService { */ async list(selector: FilterableUserProps, config = {}): Promise { const manager = this.manager_ - const userRepo = manager.getCustomRepository(this.userRepository_) + const userRepo = manager.withRepository(this.userRepository_) return await userRepo.find(buildQuery(selector, config)) } @@ -88,7 +88,7 @@ class UserService extends TransactionBaseService { } const manager = this.manager_ - const userRepo = manager.getCustomRepository(this.userRepository_) + const userRepo = manager.withRepository(this.userRepository_) const query = buildQuery({ id: userId }, config) const user = await userRepo.findOne(query) @@ -115,7 +115,7 @@ class UserService extends TransactionBaseService { relations: string[] = [] ): Promise { const manager = this.manager_ - const userRepo = manager.getCustomRepository(this.userRepository_) + const userRepo = manager.withRepository(this.userRepository_) const user = await userRepo.findOne({ where: { api_token: apiToken }, @@ -144,7 +144,7 @@ class UserService extends TransactionBaseService { config: FindConfig = {} ): Promise { const manager = this.manager_ - const userRepo = manager.getCustomRepository(this.userRepository_) + const userRepo = manager.withRepository(this.userRepository_) const query = buildQuery({ email: email.toLowerCase() }, config) const user = await userRepo.findOne(query) @@ -178,7 +178,7 @@ class UserService extends TransactionBaseService { */ async create(user: CreateUserInput, password: string): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const userRepo = manager.getCustomRepository(this.userRepository_) + const userRepo = manager.withRepository(this.userRepository_) const createData = { ...user } as CreateUserInput & { password_hash: string @@ -212,7 +212,7 @@ class UserService extends TransactionBaseService { */ async update(userId: string, update: UpdateUserInput): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const userRepo = manager.getCustomRepository(this.userRepository_) + const userRepo = manager.withRepository(this.userRepository_) const user = await this.retrieve(userId) @@ -237,7 +237,7 @@ class UserService extends TransactionBaseService { } for (const [key, value] of Object.entries(rest)) { - user[key as keyof User] = value + user[key] = value } const updatedUser = await userRepo.save(user) @@ -258,7 +258,7 @@ class UserService extends TransactionBaseService { */ async delete(userId: string): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const userRepo = manager.getCustomRepository(this.userRepository_) + const userRepo = manager.withRepository(this.userRepository_) const analyticsServiceTx = this.analyticsConfigService_.withTransaction(manager) @@ -291,7 +291,7 @@ class UserService extends TransactionBaseService { */ async setPassword_(userId: string, password: string): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { - const userRepo = manager.getCustomRepository(this.userRepository_) + const userRepo = manager.withRepository(this.userRepository_) const user = await this.retrieve(userId) diff --git a/packages/medusa/src/strategies/__tests__/price-selection.js b/packages/medusa/src/strategies/__tests__/price-selection.js index dcedc69f32..69487625f6 100644 --- a/packages/medusa/src/strategies/__tests__/price-selection.js +++ b/packages/medusa/src/strategies/__tests__/price-selection.js @@ -216,7 +216,7 @@ const executeTest = } const mockEntityManager = { - getCustomRepository: (repotype) => mockMoneyAmountRepository, + withRepository: (repotype) => mockMoneyAmountRepository, } const featureFlagRouter = new FlagRouter({ diff --git a/packages/medusa/src/strategies/cart-completion.ts b/packages/medusa/src/strategies/cart-completion.ts index 8c3c7ce0ef..fd9173c282 100644 --- a/packages/medusa/src/strategies/cart-completion.ts +++ b/packages/medusa/src/strategies/cart-completion.ts @@ -181,6 +181,8 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy { "discounts.rule", "gift_cards", "items", + "items.variant", + "items.variant.product", "items.adjustments", "region", "region.tax_rates", @@ -262,7 +264,7 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy { const cartServiceTx = this.cartService_.withTransaction(manager) const cart = await cartServiceTx.retrieveWithTotals(id, { - relations: ["region", "payment", "payment_sessions"], + relations: ["region", "payment", "payment_sessions", "items.variant.product",], }) let allowBackorder = false diff --git a/packages/medusa/src/strategies/price-selection.ts b/packages/medusa/src/strategies/price-selection.ts index 42eb2e8d1e..b17c6831fd 100644 --- a/packages/medusa/src/strategies/price-selection.ts +++ b/packages/medusa/src/strategies/price-selection.ts @@ -79,7 +79,7 @@ class PriceSelectionStrategy extends AbstractPriceSelectionStrategy { variant_id: string, context: PriceSelectionContext ): Promise { - const moneyRepo = this.manager_.getCustomRepository( + const moneyRepo = this.manager_.withRepository( this.moneyAmountRepository_ ) @@ -168,7 +168,7 @@ class PriceSelectionStrategy extends AbstractPriceSelectionStrategy { variant_id: string, context: PriceSelectionContext ): Promise { - const moneyRepo = this.manager_.getCustomRepository( + const moneyRepo = this.manager_.withRepository( this.moneyAmountRepository_ ) diff --git a/packages/medusa/src/types/common.ts b/packages/medusa/src/types/common.ts index 8b6d15eab7..044fd6202a 100644 --- a/packages/medusa/src/types/common.ts +++ b/packages/medusa/src/types/common.ts @@ -11,11 +11,15 @@ import { FindManyOptions, FindOneOptions, FindOperator, + FindOptionsSelect, + FindOptionsWhere, OrderByCondition, } from "typeorm" import { transformDate } from "../utils/validators/date-transform" import { BaseEntity } from "../interfaces" import { ClassConstructor } from "./global" +import { FindOptionsRelations } from "typeorm/find-options/FindOptionsRelations" +import { FindOptionsOrder } from "typeorm/find-options/FindOptionsOrder" /** * Utility type used to remove some optional attributes (coming from K) from a type T @@ -37,15 +41,25 @@ export type Writable = { | FindOperator } -export type ExtendedFindConfig< - TEntity, - TWhereKeys = TEntity -> = FindConfig & - (FindOneOptions | FindManyOptions) & { - where: Partial> - withDeleted?: boolean - relations?: string[] - } +export interface FindConfig { + select?: (keyof Entity)[] + skip?: number + take?: number + relations?: string[] + order?: { [K: string]: "ASC" | "DESC" } +} + +export type ExtendedFindConfig = ( + | Omit, "where" | "relations" | "select"> + | Omit, "where" | "relations" | "select"> +) & { + select?: FindOptionsSelect + relations?: FindOptionsRelations + where: FindOptionsWhere | FindOptionsWhere[] + order?: FindOptionsOrder + skip?: number + take?: number +} export type QuerySelector = Selector & { q?: string } @@ -70,14 +84,6 @@ export type TotalField = | "gift_card_total" | "gift_card_tax_total" -export interface FindConfig { - select?: (keyof Entity)[] - skip?: number - take?: number - relations?: string[] - order?: Record -} - export interface CustomFindOptions { select?: FindManyOptions["select"] where?: FindManyOptions["where"] & { diff --git a/packages/medusa/src/types/order-edit.ts b/packages/medusa/src/types/order-edit.ts index 684e667095..f6e4744e47 100644 --- a/packages/medusa/src/types/order-edit.ts +++ b/packages/medusa/src/types/order-edit.ts @@ -22,8 +22,11 @@ export type CreateOrderEditItemChangeInput = { export const defaultOrderEditRelations: string[] = [ "changes", "changes.line_item", + "changes.line_item.variant", "changes.original_line_item", + "changes.original_line_item.variant", "items", + "items.variant", "items.adjustments", "items.tax_lines", "payment_collection", diff --git a/packages/medusa/src/types/product.ts b/packages/medusa/src/types/product.ts index bd76a578ba..f1de3898ac 100644 --- a/packages/medusa/src/types/product.ts +++ b/packages/medusa/src/types/product.ts @@ -264,3 +264,11 @@ export class ProductTypeReq { @IsString() value: string } + +export type ProductFilterOptions = { + price_list_id?: FindOperator + sales_channel_id?: FindOperator + category_id?: FindOperator + include_category_children?: boolean + discount_condition_id?: string +} diff --git a/packages/medusa/src/utils/__tests__/build-query.spec.ts b/packages/medusa/src/utils/__tests__/build-query.spec.ts index f9a4819390..c6dfbf75e8 100644 --- a/packages/medusa/src/utils/__tests__/build-query.spec.ts +++ b/packages/medusa/src/utils/__tests__/build-query.spec.ts @@ -1,28 +1,294 @@ -import { In, Not } from "typeorm" -import { buildQuery } from "../build-query" +import { FindOptionsOrder, FindOptionsSelect, In, MoreThan, Not } from "typeorm" +import { addOrderToSelect, buildLegacyFieldsListFrom, buildQuery } from "../build-query" -describe('buildQuery', () => { - describe("buildQuery_", () => { - it("successfully creates query", () => { - const q = buildQuery( - { - id: "1234", - test1: ["123", "12", "1"], - test2: Not("this"), - }, - { - relations: ["1234"], +describe("buildQuery", () => { + it("successfully creates query", () => { + const date = new Date() + + const q = buildQuery( + { + id: "1234", + test1: ["123", "12", "1"], + test2: Not("this"), + date: { gt: date }, + amount: { gt: 10 }, + rule: { + type: "fixed" } - ) + }, + { + select: [ + "order", + "order.items", + "order.swaps", + "order.swaps.additional_items", + "order.discounts", + "order.discounts.rule", + "order.claims", + "order.claims.additional_items", + "additional_items", + "additional_items.variant", + "return_order", + "return_order.items", + "return_order.shipping_method", + "return_order.shipping_method.tax_lines", + ], + relations: [ + "order", + "order.items", + "order.swaps", + "order.swaps.additional_items", + "order.discounts", + "order.discounts.rule", + "order.claims", + "order.claims.additional_items", + "additional_items", + "additional_items.variant", + "return_order", + "return_order.items", + "return_order.shipping_method", + "return_order.shipping_method.tax_lines", + "items.variants", + "items.variants.product", + "items", + "items.tax_lines", + "items.adjustments", + ], + order: { + id: "ASC", + "items.id": "ASC", + "items.variant.id": "ASC" + } + } + ) - expect(q).toEqual({ - where: { - id: "1234", - test1: In(["123", "12", "1"]), - test2: Not("this"), + expect(q).toEqual({ + where: { + id: "1234", + test1: In(["123", "12", "1"]), + test2: Not("this"), + date: MoreThan(date), + amount: MoreThan(10), + rule: { + type: "fixed" + } + }, + select: { + order: { + items: true, + swaps: { + additional_items: true, + }, + discounts: { + rule: true, + }, + claims: { + additional_items: true, + }, }, - relations: ["1234"], - }) + additional_items: { + variant: true, + }, + return_order: { + items: true, + shipping_method: { + tax_lines: true, + }, + }, + }, + relations: { + order: { + items: true, + swaps: { + additional_items: true, + }, + discounts: { + rule: true, + }, + claims: { + additional_items: true, + }, + }, + additional_items: { + variant: true, + }, + return_order: { + items: true, + shipping_method: { + tax_lines: true, + }, + }, + items: { + variants: { + product: true + }, + tax_lines: true, + adjustments: true + } + }, + order: { + id: "ASC", + items: { + id: "ASC", + variant: { + id: "ASC" + } + } + } }) }) -}) \ No newline at end of file +}) + +describe("buildLegacyFieldsListFrom", () => { + it("successfully build back select object shape to list", () => { + const q = buildLegacyFieldsListFrom({ + order: { + items: true, + swaps: { + additional_items: true, + }, + discounts: { + rule: true, + }, + claims: { + additional_items: true, + }, + }, + additional_items: { + variant: true, + }, + return_order: { + items: true, + shipping_method: { + tax_lines: true, + }, + }, + }) + + expect(q.length).toBe(14) + expect(q).toEqual(expect.arrayContaining([ + "order", + "order.items", + "order.swaps", + "order.swaps.additional_items", + "order.discounts", + "order.discounts.rule", + "order.claims", + "order.claims.additional_items", + "additional_items", + "additional_items.variant", + "return_order", + "return_order.items", + "return_order.shipping_method", + "return_order.shipping_method.tax_lines", + ])) + }) + + it("successfully build back relation object shape to list", () => { + const q = buildLegacyFieldsListFrom({ + order: { + items: true, + swaps: { + additional_items: true, + }, + discounts: { + rule: true, + }, + claims: { + additional_items: true, + }, + }, + additional_items: { + variant: true, + }, + return_order: { + items: true, + shipping_method: { + tax_lines: true, + }, + }, + items: { + variants: { + product: true + }, + tax_lines: true, + adjustments: true + } + }) + + expect(q.length).toBe(19) + expect(q).toEqual(expect.arrayContaining([ + "order", + "order.items", + "order.swaps", + "order.swaps.additional_items", + "order.discounts", + "order.discounts.rule", + "order.claims", + "order.claims.additional_items", + "additional_items", + "additional_items.variant", + "return_order", + "return_order.items", + "return_order.shipping_method", + "return_order.shipping_method.tax_lines", + "items.variants", + "items.variants.product", + "items", + "items.tax_lines", + "items.adjustments", + ])) + }) + + it("successfully build back order object shape to list", () => { + const q = buildLegacyFieldsListFrom({ + id: "ASC", + items: { + id: "ASC", + variant: { + id: "ASC" + } + } + }) + + expect(q.length).toBe(5) + expect(q).toEqual(expect.arrayContaining([ + "id", + "items", + "items.id", + "items.variant", + "items.variant.id" + ])) + }) + + describe('addOrderToSelect', function () { + it("successfully add the order fields to the select object", () => { + const select: FindOptionsSelect = { + item: { + variant: { + id: true + } + } + } + + const order: FindOptionsOrder = { + item: { + variant: { + rank: "ASC" + } + } + } + + addOrderToSelect(order, select) + + expect(select).toEqual({ + item: { + variant: { + id: true, + rank: true + } + } + }) + }) + }); +}) diff --git a/packages/medusa/src/utils/build-query.ts b/packages/medusa/src/utils/build-query.ts index 0859b641f3..9117533ab4 100644 --- a/packages/medusa/src/utils/build-query.ts +++ b/packages/medusa/src/utils/build-query.ts @@ -1,10 +1,19 @@ +import { ExtendedFindConfig, FindConfig } from "../types/common" import { - ExtendedFindConfig, - FindConfig, - Selector, - Writable, -} from "../types/common" -import { FindOperator, In, IsNull, Raw } from "typeorm" + FindManyOptions, + FindOperator, + FindOptionsRelations, + FindOptionsSelect, + FindOptionsWhere, + In, + IsNull, + LessThan, + LessThanOrEqual, + MoreThan, + MoreThanOrEqual, +} from "typeorm" +import { FindOptionsOrder } from "typeorm/find-options/FindOptionsOrder" +import { isObject } from "./is-object" /** * Used to build TypeORM queries. @@ -12,77 +21,12 @@ import { FindOperator, In, IsNull, Raw } from "typeorm" * @param config The config * @return The QueryBuilderConfig */ -export function buildQuery( +export function buildQuery( selector: TWhereKeys, config: FindConfig = {} -): ExtendedFindConfig { - const build = (obj: Selector): Partial> => { - return Object.entries(obj).reduce((acc, [key, value]: any) => { - // Undefined values indicate that they have no significance to the query. - // If the query is looking for rows where a column is not set it should use null instead of undefined - if (typeof value === "undefined") { - return acc - } - - if (value === null) { - acc[key] = IsNull() - return acc - } - - const subquery: { - operator: "<" | ">" | "<=" | ">=" - value: unknown - }[] = [] - - switch (true) { - case value instanceof FindOperator: - acc[key] = value - break - case Array.isArray(value): - acc[key] = In([...(value as unknown[])]) - break - case value !== null && typeof value === "object": - Object.entries(value).map(([modifier, val]) => { - switch (modifier) { - case "lt": - subquery.push({ operator: "<", value: val }) - break - case "gt": - subquery.push({ operator: ">", value: val }) - break - case "lte": - subquery.push({ operator: "<=", value: val }) - break - case "gte": - subquery.push({ operator: ">=", value: val }) - break - default: - acc[key] = value - break - } - }) - - if (subquery.length) { - acc[key] = Raw( - (a) => - subquery - .map((s, index) => `${a} ${s.operator} :${index}`) - .join(" AND "), - subquery.map((s) => s.value) - ) - } - break - default: - acc[key] = value - break - } - - return acc - }, {} as Partial>) - } - - const query: ExtendedFindConfig = { - where: build(selector), +) { + const query: ExtendedFindConfig = { + where: buildWhere(selector), } if ("deleted_at" in selector) { @@ -90,24 +34,304 @@ export function buildQuery( } if ("skip" in config) { - query.skip = config.skip + ;(query as FindManyOptions).skip = config.skip } if ("take" in config) { - query.take = config.take + ;(query as FindManyOptions).take = config.take } - if ("relations" in config) { - query.relations = config.relations + if (config.relations) { + query.relations = buildRelations(config.relations) } - if ("select" in config) { - query.select = config.select + if (config.select) { + query.select = buildSelects(config.select as string[]) } - if ("order" in config) { - query.order = config.order + if (config.order) { + query.order = buildOrder(config.order) } return query } + +/** + * @param constraints + * + * @example + * const q = buildWhere( + * { + * id: "1234", + * test1: ["123", "12", "1"], + * test2: Not("this"), + * date: { gt: date }, + * amount: { gt: 10 }, + * }, + *) + * + * // Output + * { + * id: "1234", + * test1: In(["123", "12", "1"]), + * test2: Not("this"), + * date: MoreThan(date), + * amount: MoreThan(10) + * } + */ +function buildWhere( + constraints: TWhereKeys +): FindOptionsWhere { + const where: FindOptionsWhere = {} + for (const [key, value] of Object.entries(constraints)) { + if (value === undefined) { + continue + } + + if (value === null) { + where[key] = IsNull() + continue + } + + if (value instanceof FindOperator) { + where[key] = value + continue + } + + if (Array.isArray(value)) { + where[key] = In(value) + continue + } + + if (typeof value === "object") { + Object.entries(value).forEach(([objectKey, objectValue]) => { + switch (objectKey) { + case "lt": + where[key] = LessThan(objectValue) + break + case "gt": + where[key] = MoreThan(objectValue) + break + case "lte": + where[key] = LessThanOrEqual(objectValue) + break + case "gte": + where[key] = MoreThanOrEqual(objectValue) + break + default: + if (objectValue != undefined && typeof objectValue === "object") { + where[key] = buildWhere(objectValue) + return + } + where[key] = value + } + return + }) + + continue + } + + where[key] = value + } + + return where +} + +/** + * Revert new object structure of find options to the legacy structure of previous version + * @example + * input: { + * test: { + * test1: true, + * test2: true, + * test3: { + * test4: true + * }, + * }, + * test2: true + * } + * output: ['test.test1', 'test.test2', 'test.test3.test4', 'test2'] + * @param input + */ +export function buildLegacyFieldsListFrom( + input: + | FindOptionsWhere + | FindOptionsSelect + | FindOptionsOrder + | FindOptionsRelations = {} +): (keyof TEntity)[] { + if (!Object.keys(input).length) { + return [] + } + + const output: Set = new Set(Object.keys(input)) + + for (const key of Object.keys(input)) { + if (input[key] != undefined && typeof input[key] === "object") { + const deepRes = buildLegacyFieldsListFrom(input[key]) + + const items = deepRes.reduce((acc, val) => { + acc.push(`${key}.${val}`) + return acc + }, [] as string[]) + + items.forEach((item) => output.add(item)) + continue + } + + output.add(key) + } + + return Array.from(output) as (keyof TEntity)[] +} + +export function buildSelects( + selectCollection: string[] +): FindOptionsSelect { + return buildRelationsOrSelect(selectCollection) as FindOptionsSelect +} + +export function buildRelations( + relationCollection: string[] +): FindOptionsRelations { + return buildRelationsOrSelect( + relationCollection + ) as FindOptionsRelations +} + +export function addOrderToSelect( + order: FindOptionsOrder, + select: FindOptionsSelect +): void { + for (const orderBy of Object.keys(order)) { + if (isObject(order[orderBy])) { + select[orderBy] = + select[orderBy] && isObject(select[orderBy]) ? select[orderBy] : {} + addOrderToSelect(order[orderBy], select[orderBy]) + continue + } + + select[orderBy] = isObject(select[orderBy]) + ? { ...select[orderBy], id: true, [orderBy]: true } + : true + } +} + +/** + * Convert an collection of dot string into a nested object + * @example + * input: [ + * order, + * order.items, + * order.swaps, + * order.swaps.additional_items, + * order.discounts, + * order.discounts.rule, + * order.claims, + * order.claims.additional_items, + * additional_items, + * additional_items.variant, + * return_order, + * return_order.items, + * return_order.shipping_method, + * return_order.shipping_method.tax_lines + * ] + * output: { + * "order": { + * "items": true, + * "swaps": { + * "additional_items": true + * }, + * "discounts": { + * "rule": true + * }, + * "claims": { + * "additional_items": true + * } + * }, + * "additional_items": { + * "variant": true + * }, + * "return_order": { + * "items": true, + * "shipping_method": { + * "tax_lines": true + * } + * } + * } + * @param collection + */ +function buildRelationsOrSelect( + collection: string[] +): FindOptionsRelations | FindOptionsSelect { + const output: FindOptionsRelations | FindOptionsSelect = {} + + for (const relation of collection) { + if (relation.indexOf(".") > -1) { + const nestedRelations = relation.split(".") + + let parent = output + + while (nestedRelations.length > 1) { + const nestedRelation = nestedRelations.shift() as string + parent = parent[nestedRelation] = + parent[nestedRelation] !== true && + typeof parent[nestedRelation] === "object" + ? parent[nestedRelation] + : {} + } + + parent[nestedRelations[0]] = true + + continue + } + + output[relation] = output[relation] ?? true + } + + return output +} + +/** + * Convert an order of dot string into a nested object + * @example + * input: { id: "ASC", "items.title": "ASC", "items.variant.title": "ASC" } + * output: { + * "id": "ASC", + * "items": { + * "id": "ASC", + * "variant": { + * "title": "ASC" + * } + * }, + * } + * @param orderBy + */ +function buildOrder(orderBy: { + [k: string]: "ASC" | "DESC" +}): FindOptionsOrder { + const output: FindOptionsOrder = {} + + const orderKeys = Object.keys(orderBy) + + for (const order of orderKeys) { + if (order.indexOf(".") > -1) { + const nestedOrder = order.split(".") + + let parent = output + + while (nestedOrder.length > 1) { + const nestedRelation = nestedOrder.shift() as string + parent = parent[nestedRelation] = parent[nestedRelation] ?? {} + } + + parent[nestedOrder[0]] = orderBy[order] + + continue + } + + output[order] = orderBy[order] + } + + return output +} diff --git a/packages/medusa/src/utils/idempotency/run-idempotency-step.ts b/packages/medusa/src/utils/idempotency/run-idempotency-step.ts index b40f3deabd..2e14e449f6 100644 --- a/packages/medusa/src/utils/idempotency/run-idempotency-step.ts +++ b/packages/medusa/src/utils/idempotency/run-idempotency-step.ts @@ -13,7 +13,11 @@ export type RunIdempotencyStepOptions = { } export async function runIdempotencyStep( - handler: ({ manager: EntityManager }) => Promise, + handler: ({ + manager, + }: { + manager: EntityManager + }) => Promise, { manager, idempotencyKey, diff --git a/packages/medusa/src/utils/index.ts b/packages/medusa/src/utils/index.ts index f4d5653093..3786e860e8 100644 --- a/packages/medusa/src/utils/index.ts +++ b/packages/medusa/src/utils/index.ts @@ -4,6 +4,8 @@ export * from "./validate-id" export * from "./generate-entity-id" export * from "./remove-undefined-properties" export * from "./is-string" +export * from "./is-date" +export * from "./is-object" export * from "./calculate-price-tax-amount" export * from "./csv-cell-content-formatter" export * from "./exception-formatter" diff --git a/packages/medusa/src/utils/is-date.ts b/packages/medusa/src/utils/is-date.ts new file mode 100644 index 0000000000..97e98072d3 --- /dev/null +++ b/packages/medusa/src/utils/is-date.ts @@ -0,0 +1,4 @@ +export function isDate(value: any): value is Date { + const date = new Date(value) + return !isNaN(date.valueOf()) +} diff --git a/packages/medusa/src/utils/is-object.ts b/packages/medusa/src/utils/is-object.ts new file mode 100644 index 0000000000..778a601412 --- /dev/null +++ b/packages/medusa/src/utils/is-object.ts @@ -0,0 +1,3 @@ +export function isObject(obj: unknown): obj is object { + return typeof obj === "object" && !!obj +} diff --git a/packages/medusa/src/utils/naming-strategy.ts b/packages/medusa/src/utils/naming-strategy.ts index 10e1df06d1..74463244df 100644 --- a/packages/medusa/src/utils/naming-strategy.ts +++ b/packages/medusa/src/utils/naming-strategy.ts @@ -1,13 +1,17 @@ +// Since typeorm require us to use ES6 and that migrating require a lot of work +// one solution is to override directly the one from typeorm so that there is no complain about +// the output build import { DefaultNamingStrategy } from "typeorm" -export class ShortenedNamingStrategy extends DefaultNamingStrategy { - eagerJoinRelationAlias(alias: string, propertyPath: string): string { - const path = propertyPath - .split(".") - .map((p) => p.substring(0, 2)) - .join("_") - const out = alias + "_" + path - const match = out.match(/_/g) || [] - return out + match.length - } +DefaultNamingStrategy.prototype.eagerJoinRelationAlias = function ( + alias: string, + propertyPath: string +): string { + const path = propertyPath + .split(".") + .map((p) => p.substring(0, 2)) + .join("_") + const out = alias + "_" + path + const match = out.match(/_/g) || [] + return out + match.length } diff --git a/packages/medusa/src/utils/repository.ts b/packages/medusa/src/utils/repository.ts index b386c41bcd..36a13c6a6d 100644 --- a/packages/medusa/src/utils/repository.ts +++ b/packages/medusa/src/utils/repository.ts @@ -1,5 +1,10 @@ import { flatten, groupBy, map, merge } from "lodash" -import { EntityMetadata, Repository, SelectQueryBuilder } from "typeorm" +import { + EntityMetadata, + ObjectLiteral, + Repository, + SelectQueryBuilder, +} from "typeorm" import { ExtendedFindConfig } from "../types/common" /** @@ -12,7 +17,7 @@ import { ExtendedFindConfig } from "../types/common" * @param select * @param customJoinBuilders */ -export async function queryEntityWithIds( +export async function queryEntityWithIds( repository: Repository, entityIds: string[], groupedRelations: { [toplevel: string]: string[] }, @@ -89,9 +94,9 @@ export async function queryEntityWithIds( * @param shouldCount * @param customJoinBuilders */ -export async function queryEntityWithoutRelations( +export async function queryEntityWithoutRelations( repository: Repository, - optionsWithoutRelations: Omit, "relations">, + optionsWithoutRelations: Omit, "relations">, shouldCount = false, customJoinBuilders: (( qb: SelectQueryBuilder, @@ -188,7 +193,7 @@ export function mergeEntitiesWithRelations( * @param alias * @param shouldJoin In case a join is already applied elsewhere and therefore you want to avoid to re joining the data in that case you can return false for specific relations */ -export function applyOrdering({ +export function applyOrdering({ repository, order, qb, diff --git a/packages/medusa/tsconfig.json b/packages/medusa/tsconfig.json index b73ee18358..e5d942d558 100644 --- a/packages/medusa/tsconfig.json +++ b/packages/medusa/tsconfig.json @@ -20,7 +20,8 @@ "noImplicitThis": true, "allowJs": true, "skipLibCheck": true, - "downlevelIteration": true // to use ES5 specific tooling + "downlevelIteration": true, // to use ES5 specific tooling + "resolveJsonModule": true, }, "include": ["./src/**/*", "index.d.ts"], "exclude": [ diff --git a/packages/stock-location/package.json b/packages/stock-location/package.json index 62c53b9656..6a0fec7a44 100644 --- a/packages/stock-location/package.json +++ b/packages/stock-location/package.json @@ -21,6 +21,7 @@ "cross-env": "^5.2.1", "jest": "^25.5.4", "ts-jest": "^25.5.1", + "typeorm": "^0.3.11", "typescript": "^4.4.4" }, "scripts": { @@ -32,7 +33,6 @@ }, "peerDependencies": { "@medusajs/medusa": "^1.7.7", - "medusa-interfaces": "1.3.6", - "typeorm": "^0.2.31" + "typeorm": "^0.3.11" } } diff --git a/packages/stock-location/src/services/stock-location.ts b/packages/stock-location/src/services/stock-location.ts index 9d57fc100a..afd08dc8dd 100644 --- a/packages/stock-location/src/services/stock-location.ts +++ b/packages/stock-location/src/services/stock-location.ts @@ -240,7 +240,7 @@ export default class StockLocationService extends TransactionBaseService { const locationAddressRepo = manager.getRepository(StockLocationAddress) const existingAddress = await locationAddressRepo.findOne({ - id: addressId, + where: { id: addressId } }) if (!existingAddress) { throw new MedusaError( diff --git a/yarn.lock b/yarn.lock index 30cd4eea00..62a834ef29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4734,11 +4734,11 @@ __metadata: cross-env: ^5.2.1 jest: ^25.5.4 ts-jest: ^25.5.1 - typeorm: ^0.2.31 + typeorm: ^0.3.11 typescript: ^4.4.4 peerDependencies: "@medusajs/medusa": 1.7.7 - medusa-interfaces: 1.3.6 + typeorm: ^0.3.11 languageName: unknown linkType: soft @@ -4888,7 +4888,7 @@ __metadata: winston: ^3.8.2 peerDependencies: medusa-interfaces: 1.3.6 - typeorm: 0.2.x + typeorm: ^0.3.11 bin: medusa: ./cli.js languageName: unknown @@ -4902,11 +4902,11 @@ __metadata: cross-env: ^5.2.1 jest: ^25.5.4 ts-jest: ^25.5.1 + typeorm: ^0.3.11 typescript: ^4.4.4 peerDependencies: "@medusajs/medusa": ^1.7.7 - medusa-interfaces: 1.3.6 - typeorm: ^0.2.31 + typeorm: ^0.3.11 languageName: unknown linkType: soft @@ -13999,6 +13999,13 @@ __metadata: languageName: node linkType: hard +"date-fns@npm:^2.28.0": + version: 2.29.3 + resolution: "date-fns@npm:2.29.3" + checksum: aa9128c876ef69a05988029d6aa3d7e5c47a1e978f18b77b48126683d1a2e6605a16c3f5293ca9f4ca790d0755b5061fcea5b469f097871cd53f6590a5c1adc4 + languageName: node + linkType: hard + "dayjs@npm:1.10.4": version: 1.10.4 resolution: "dayjs@npm:1.10.4" @@ -14706,6 +14713,13 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.0.0": + version: 16.0.3 + resolution: "dotenv@npm:16.0.3" + checksum: 109457ac5f9e930ca8066ea33887b6f839ab24d647a7a8b49ddcd1f32662e2c35591c5e5b9819063e430148a664d0927f0cbe60cf9575d89bc524f47ff7e78f0 + languageName: node + linkType: hard + "dotenv@npm:^7.0.0": version: 7.0.0 resolution: "dotenv@npm:7.0.0" @@ -19804,7 +19818,7 @@ __metadata: faker: ^5.5.3 jest: ^26.6.3 medusa-interfaces: "*" - typeorm: ^0.2.31 + typeorm: ^0.3.11 languageName: unknown linkType: soft @@ -19822,7 +19836,7 @@ __metadata: medusa-fulfillment-webshipper: "*" medusa-interfaces: "*" medusa-plugin-sendgrid: "*" - typeorm: ^0.2.31 + typeorm: ^0.3.11 languageName: unknown linkType: soft @@ -19837,7 +19851,7 @@ __metadata: babel-preset-medusa-package: "*" jest: ^26.6.3 medusa-interfaces: "*" - typeorm: ^0.2.31 + typeorm: ^0.3.11 languageName: unknown linkType: soft @@ -22811,7 +22825,7 @@ __metadata: languageName: node linkType: hard -"js-yaml@npm:^4.0.0, js-yaml@npm:^4.1.0": +"js-yaml@npm:^4.1.0": version: 4.1.0 resolution: "js-yaml@npm:4.1.0" dependencies: @@ -24820,7 +24834,6 @@ __metadata: jest: ^25.5.4 medusa-core-utils: ^1.1.39 medusa-test-utils: ^1.1.37 - typeorm: ^0.2.29 typescript: ^4.4.4 peerDependencies: medusa-core-utils: ^1.1.39 @@ -31248,7 +31261,7 @@ __metadata: typedoc-plugin-markdown: ^3.13.4 typedoc-plugin-merge-modules: ^4.0.1 typedoc-plugin-reference-excluder: ^1.0.0 - typeorm: ^0.2.31 + typeorm: ^0.3.11 languageName: unknown linkType: soft @@ -34672,44 +34685,48 @@ __metadata: languageName: node linkType: hard -"typeorm@npm:^0.2.29, typeorm@npm:^0.2.31": - version: 0.2.45 - resolution: "typeorm@npm:0.2.45" +"typeorm@npm:^0.3.11": + version: 0.3.11 + resolution: "typeorm@npm:0.3.11" dependencies: "@sqltools/formatter": ^1.2.2 app-root-path: ^3.0.0 buffer: ^6.0.3 chalk: ^4.1.0 cli-highlight: ^2.1.11 - debug: ^4.3.1 - dotenv: ^8.2.0 - glob: ^7.1.6 - js-yaml: ^4.0.0 + date-fns: ^2.28.0 + debug: ^4.3.3 + dotenv: ^16.0.0 + glob: ^7.2.0 + js-yaml: ^4.1.0 mkdirp: ^1.0.4 reflect-metadata: ^0.1.13 sha.js: ^2.4.11 - tslib: ^2.1.0 + tslib: ^2.3.1 uuid: ^8.3.2 xml2js: ^0.4.23 - yargs: ^17.0.1 - zen-observable-ts: ^1.0.0 + yargs: ^17.3.1 peerDependencies: - "@sap/hana-client": ^2.11.14 - better-sqlite3: ^7.1.2 + "@google-cloud/spanner": ^5.18.0 + "@sap/hana-client": ^2.12.25 + better-sqlite3: ^7.1.2 || ^8.0.0 hdb-pool: ^0.1.6 - ioredis: ^4.28.3 + ioredis: ^5.0.4 mongodb: ^3.6.0 - mssql: ^6.3.1 + mssql: ^7.3.0 mysql2: ^2.2.5 oracledb: ^5.1.0 pg: ^8.5.1 pg-native: ^3.0.0 pg-query-stream: ^4.0.0 - redis: ^3.1.1 + redis: ^3.1.1 || ^4.0.0 sql.js: ^1.4.0 - sqlite3: ^5.0.2 + sqlite3: ^5.0.3 + ts-node: ^10.7.0 typeorm-aurora-data-api-driver: ^2.0.0 peerDependenciesMeta: + "@google-cloud/spanner": + optional: true "@sap/hana-client": optional: true better-sqlite3: @@ -34738,11 +34755,15 @@ __metadata: optional: true sqlite3: optional: true + ts-node: + optional: true typeorm-aurora-data-api-driver: optional: true bin: typeorm: cli.js - checksum: 005655de6670d4ca7fcb85c7b865f1a21b1191bc810f4cee4f4424c8018c238f927eedda916de07a28dde51577bf44cc56a6f5f2080e93eeb1bdb7ee64e7609c + typeorm-ts-node-commonjs: cli-ts-node-commonjs.js + typeorm-ts-node-esm: cli-ts-node-esm.js + checksum: a72d406658754ca9cfd67a075ec234740bf4f96fb8a9ee283fe0eb92872357a977233dbde009063280fe059cd2af3ef72cd38dbc29631eed0c2e5f9355867bfc languageName: node linkType: hard @@ -36796,22 +36817,6 @@ __metadata: languageName: node linkType: hard -"zen-observable-ts@npm:^1.0.0": - version: 1.2.5 - resolution: "zen-observable-ts@npm:1.2.5" - dependencies: - zen-observable: 0.8.15 - checksum: 21d586f3d0543e1d6f05d9333a137b407dbf337907c1ee1c2fa7a7da044f7e1262e4baf4ef8902f230c6f5acb561047659eb7df73df33307233cc451efe46db1 - languageName: node - linkType: hard - -"zen-observable@npm:0.8.15": - version: 0.8.15 - resolution: "zen-observable@npm:0.8.15" - checksum: 71cc2f2bbb537300c3f569e25693d37b3bc91f225cefce251a71c30bc6bb3e7f8e9420ca0eb57f2ac9e492b085b8dfa075fd1e8195c40b83c951dd59c6e4fbf8 - languageName: node - linkType: hard - "zwitch@npm:^1.0.0": version: 1.0.5 resolution: "zwitch@npm:1.0.5"