From a7be5d7b6d4a3ee232e4657e141bc23de31ece39 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Fri, 2 Feb 2024 15:20:32 +0100 Subject: [PATCH] chore: Abstract module service (#6188) **What** - Remove services that do not have any custom business and replace them with a simple interfaces - Abstract module service provide the following base implementation - retrieve - list - listAndCount - delete - softDelete - restore The above methods are created for the main model and also for each other models for which a config is provided all method such as list, listAndCount, delete, softDelete and restore are pluralized with the model it refers to **Migration** - [x] product - [x] pricing - [x] promotion - [x] cart - [x] auth - [x] customer - [x] payment - [x] Sales channel - [x] Workflow-* **Usage** **Module** The module service can now extend the ` ModulesSdkUtils.abstractModuleServiceFactory` which returns a class with the default implementation for each method and each model following the standard naming convention mentioned above. This factory have 3 template arguments being the container, the main model DTO and an object representing the other model with a config object that contains at list the DTO and optionally a singular and plural property in case it needs to be set manually. It looks like the following: ```ts export default class PricingModuleService extends ModulesSdkUtils.abstractModuleServiceFactory< InjectedDependencies, PricingTypes.PriceSetDTO, { Currency: { dto: PricingTypes.CurrencyDTO } MoneyAmount: { dto: PricingTypes.MoneyAmountDTO } PriceSetMoneyAmount: { dto: PricingTypes.PriceSetMoneyAmountDTO } PriceSetMoneyAmountRules: { dto: PricingTypes.PriceSetMoneyAmountRulesDTO } PriceRule: { dto: PricingTypes.PriceRuleDTO } RuleType: { dto: PricingTypes.RuleTypeDTO } PriceList: { dto: PricingTypes.PriceListDTO } PriceListRule: { dto: PricingTypes.PriceListRuleDTO } } >(PriceSet, generateMethodForModels, entityNameToLinkableKeysMap) implements PricingTypes.IPricingModuleService { // ... } ``` In the above, the singular and plural can be inferred as there is no tricky naming. Also, the default implementation does not remove the fact that you need to provides all the overloads etc in your module service interface. The above will provide a default implementation following the interface `AbstractModuleService` which is also auto generated, hence you will have the following methods available: **for the main model** - list - retrieve - listAndCount - delete - softDelete - restore **for the other models** - list**MyModels** - retrieve**MyModel** - listAndCount**MyModels** - delete**MyModels** - softDelete**MyModels** - restore**MyModels** **Internal module service** The internal module service can now extend `ModulesSdkUtils.internalModuleServiceFactory` which takes only one template argument which is the container type. All internal services provides a default implementation for all retrieve, list, listAndCount, create, update, delete, softDelete, restore methods which follow the following interface `ModulesSdkTypes.InternalModuleService`: ```ts export interface InternalModuleService< TEntity extends {}, TContainer extends object = object > { get __container__(): TContainer retrieve( idOrObject: string, config?: FindConfig, sharedContext?: Context ): Promise retrieve( idOrObject: object, config?: FindConfig, sharedContext?: Context ): Promise list( filters?: FilterQuery | BaseFilterable>, config?: FindConfig, sharedContext?: Context ): Promise listAndCount( filters?: FilterQuery | BaseFilterable>, config?: FindConfig, sharedContext?: Context ): Promise<[TEntity[], number]> create(data: any[], sharedContext?: Context): Promise create(data: any, sharedContext?: Context): Promise update(data: any[], sharedContext?: Context): Promise update(data: any, sharedContext?: Context): Promise update( selectorAndData: { selector: FilterQuery | BaseFilterable> data: any }, sharedContext?: Context ): Promise update( selectorAndData: { selector: FilterQuery | BaseFilterable> data: any }[], sharedContext?: Context ): Promise delete(idOrSelector: string, sharedContext?: Context): Promise delete(idOrSelector: string[], sharedContext?: Context): Promise delete(idOrSelector: object, sharedContext?: Context): Promise delete(idOrSelector: object[], sharedContext?: Context): Promise delete( idOrSelector: { selector: FilterQuery | BaseFilterable> }, sharedContext?: Context ): Promise softDelete( idsOrFilter: string[] | InternalFilterQuery, sharedContext?: Context ): Promise<[TEntity[], Record]> restore( idsOrFilter: string[] | InternalFilterQuery, sharedContext?: Context ): Promise<[TEntity[], Record]> upsert(data: any[], sharedContext?: Context): Promise upsert(data: any, sharedContext?: Context): Promise } ``` When a service is auto generated you can use that interface to type your class property representing the expected internal service. **Repositories** The repositories can now extend `DALUtils.mikroOrmBaseRepositoryFactory` which takes one template argument being the entity or the template entity and provides all the default implementation. If the repository is auto generated you can type it using the `RepositoryService` interface. Here is the new interface typings. ```ts export interface RepositoryService extends BaseRepositoryService { find(options?: FindOptions, context?: Context): Promise findAndCount( options?: FindOptions, context?: Context ): Promise<[T[], number]> create(data: any[], context?: Context): Promise // Becareful here, if you have a custom internal service, the update data should never be the entity otherwise // both entity and update will point to the same ref and create issues with mikro orm update(data: { entity; update }[], context?: Context): Promise delete( idsOrPKs: FilterQuery & BaseFilterable>, context?: Context ): Promise /** * Soft delete entities and cascade to related entities if configured. * * @param idsOrFilter * @param context * * @returns [T[], Record] the second value being the map of the entity names and ids that were soft deleted */ softDelete( idsOrFilter: string[] | InternalFilterQuery, context?: Context ): Promise<[T[], Record]> restore( idsOrFilter: string[] | InternalFilterQuery, context?: Context ): Promise<[T[], Record]> upsert(data: any[], context?: Context): Promise } ``` --- .../customer/store/list-customer-addresses.ts | 20 +- .../admin/create-product-variant.spec.ts | 5 +- .../workflows/product/create-product.ts | 4 +- .../services/auth-provider/index.spec.ts | 6 +- .../services/auth-user/index.spec.ts | 4 +- .../services/module/auth-provider.spec.ts | 22 +- .../services/module/auth-user.spec.ts | 30 +- .../services/module/providers.spec.ts | 3 +- packages/auth/src/providers/google.ts | 17 +- packages/auth/src/services/auth-module.ts | 223 ++--- packages/auth/src/services/auth-provider.ts | 24 - packages/auth/src/services/auth-user.ts | 25 +- packages/auth/src/services/index.ts | 1 - packages/auth/src/types/repositories/index.ts | 26 - packages/cart/src/services/address.ts | 23 - packages/cart/src/services/cart-module.ts | 346 ++------ packages/cart/src/services/cart.ts | 23 - packages/cart/src/services/index.ts | 9 - .../cart/src/services/line-item-adjustment.ts | 26 - .../cart/src/services/line-item-tax-line.ts | 26 - packages/cart/src/services/line-item.ts | 23 - .../services/shipping-method-adjustment.ts | 26 - .../src/services/shipping-method-tax-line.ts | 22 - packages/cart/src/services/shipping-method.ts | 23 - packages/cart/src/types/index.ts | 1 - packages/cart/src/types/repositories.ts | 114 --- packages/cart/src/types/shipping-method.ts | 2 +- .../steps/delete-customer-groups.ts | 4 +- .../steps/update-customer-groups.ts | 6 +- .../src/customer/steps/create-addresses.ts | 6 +- .../src/customer/steps/delete-addresses.ts | 2 +- .../maybe-unset-default-billing-addresses.ts | 8 +- .../maybe-unset-default-shipping-addresses.ts | 8 +- .../src/customer/steps/update-addresses.ts | 4 +- .../steps/utils/unset-address-for-create.ts | 2 +- .../steps/utils/unset-address-for-update.ts | 2 +- .../services/customer-module/index.spec.ts | 32 +- packages/customer/src/models/address.ts | 15 +- packages/customer/src/services/address.ts | 23 - .../src/services/customer-group-customer.ts | 25 - .../customer/src/services/customer-group.ts | 23 - .../customer/src/services/customer-module.ts | 618 ++++---------- packages/customer/src/services/customer.ts | 22 - packages/customer/src/services/index.ts | 4 - packages/customer/src/types/index.ts | 5 +- .../src/types/{ => services}/address.ts | 0 .../types/services/customer-group-customer.ts | 5 + packages/customer/src/types/services/index.ts | 2 + .../services/payment-module/index.spec.ts | 2 +- packages/payment/src/services/index.ts | 1 - .../src/services/payment-collection.ts | 26 - .../payment/src/services/payment-module.ts | 132 +-- packages/payment/src/types/repositories.ts | 18 - .../__tests__/services/currency/index.spec.ts | 2 +- .../services/money-amount/index.spec.ts | 2 +- .../services/price-list-rule/index.spec.ts | 2 +- .../services/price-list/index.spec.ts | 2 +- .../services/price-rule/index.spec.ts | 2 +- .../index.spec.ts | 2 +- .../services/price-set/index.spec.ts | 2 +- .../services/pricing-module/currency.spec.ts | 2 +- .../pricing-module/money-amount.spec.ts | 6 +- .../pricing-module/price-list-rule.spec.ts | 8 +- .../pricing-module/price-list.spec.ts | 2 +- .../pricing-module/price-rule.spec.ts | 2 +- .../price-set-money-amount-rules.spec.ts | 2 +- .../services/pricing-module/price-set.spec.ts | 2 +- .../services/pricing-module/rule-type.spec.ts | 2 +- .../services/rule-type/index.spec.ts | 2 +- .../src/services/__fixtures__/currency.ts | 11 +- .../src/services/__tests__/currency.spec.ts | 43 +- packages/pricing/src/services/currency.ts | 23 - packages/pricing/src/services/index.ts | 6 - packages/pricing/src/services/money-amount.ts | 27 - .../src/services/price-list-rule-value.ts | 32 +- .../pricing/src/services/price-list-rule.ts | 55 +- packages/pricing/src/services/price-list.ts | 41 +- packages/pricing/src/services/price-rule.ts | 29 +- .../services/price-set-money-amount-rules.ts | 27 - .../src/services/price-set-money-amount.ts | 27 - .../src/services/price-set-rule-type.ts | 27 - packages/pricing/src/services/price-set.ts | 28 - .../pricing/src/services/pricing-module.ts | 785 ++---------------- packages/pricing/src/services/rule-type.ts | 62 +- .../pricing/src/types/repositories/index.ts | 157 ---- .../services/product-collection/index.ts | 2 +- .../product-module-service/products.spec.ts | 16 + .../services/product-option/index.ts | 2 +- .../__tests__/services/product-tag/index.ts | 2 +- .../__tests__/services/product-type/index.ts | 2 +- .../services/product-variant/index.ts | 2 +- .../__tests__/services/product/index.ts | 4 +- packages/product/src/models/product.ts | 2 +- .../product/src/repositories/product-image.ts | 2 +- packages/product/src/repositories/product.ts | 23 +- .../src/services/__fixtures__/product.ts | 10 +- .../src/services/__tests__/product.spec.ts | 43 +- packages/product/src/services/index.ts | 2 - .../src/services/product-collection.ts | 76 +- .../product/src/services/product-image.ts | 18 - .../src/services/product-module-service.ts | 657 ++------------- .../src/services/product-option-value.ts | 23 - .../product/src/services/product-option.ts | 25 +- packages/product/src/services/product-tag.ts | 25 +- packages/product/src/services/product-type.ts | 25 +- .../product/src/services/product-variant.ts | 18 +- packages/product/src/services/product.ts | 29 +- packages/product/src/types/index.ts | 1 - packages/product/src/types/repositories.ts | 100 --- .../promotion-module/campaign.spec.ts | 6 +- .../promotion-module/promotion.spec.ts | 16 +- .../promotion/src/repositories/campaign.ts | 14 +- .../src/services/application-method.ts | 27 - .../promotion/src/services/campaign-budget.ts | 27 - packages/promotion/src/services/campaign.ts | 27 - packages/promotion/src/services/index.ts | 6 - .../src/services/promotion-module.ts | 358 ++------ .../src/services/promotion-rule-value.ts | 30 - .../promotion/src/services/promotion-rule.ts | 27 - packages/promotion/src/services/promotion.ts | 27 - packages/promotion/src/types/index.ts | 1 - packages/promotion/src/types/repositories.ts | 91 -- .../services/__fixtures__/sales-channel.ts | 12 +- .../services/__tests__/sales-channle.spec.ts | 22 +- packages/sales-channel/src/services/index.ts | 1 - .../src/services/sales-channel-module.ts | 174 +--- .../src/services/sales-channel.ts | 24 - .../sales-channel/src/types/repositories.ts | 15 - .../types/src/auth/common/auth-provider.ts | 1 + packages/types/src/auth/service.ts | 4 +- packages/types/src/common/common.ts | 22 +- packages/types/src/customer/service.ts | 54 +- packages/types/src/dal/repository-service.ts | 34 +- packages/types/src/modules-sdk/index.ts | 1 + .../modules-sdk/internal-module-service.ts | 81 ++ .../types/src/modules-sdk/module-service.ts | 0 packages/types/src/payment/service.ts | 4 +- packages/types/src/pricing/service.ts | 19 +- packages/types/src/product/service.ts | 30 +- .../src/common/__tests__/pluralize.spec.ts | 33 + packages/utils/src/common/index.ts | 1 + packages/utils/src/common/plurailze.ts | 27 + packages/utils/src/dal/index.ts | 1 - .../src/dal/mikro-orm/mikro-orm-repository.ts | 210 ++--- packages/utils/src/dal/mikro-orm/utils.ts | 33 +- packages/utils/src/dal/repository.ts | 104 --- .../abstract-module-service-factory.spec.ts | 201 +++++ .../internal-module-service-factory.spec.ts | 240 ++++++ .../abstract-module-service-factory.ts | 527 ++++++++++++ .../modules-sdk/abstract-service-factory.ts | 257 ------ .../modules-sdk/decorators/inject-manager.ts | 11 +- .../decorators/inject-transaction-manager.ts | 10 +- packages/utils/src/modules-sdk/index.ts | 3 +- .../internal-module-service-factory.ts | 442 ++++++++++ .../loaders/container-loader-factory.ts | 4 +- .../src/services/index.ts | 1 - .../src/services/workflow-execution.ts | 21 - .../src/services/workflows-module.ts | 13 +- .../utils/workflow-orchestrator-storage.ts | 10 +- .../src/services/index.ts | 1 - .../src/services/workflow-execution.ts | 21 - .../src/services/workflows-module.ts | 15 +- .../utils/workflow-orchestrator-storage.ts | 6 +- 163 files changed, 2867 insertions(+), 5080 deletions(-) delete mode 100644 packages/auth/src/services/auth-provider.ts delete mode 100644 packages/cart/src/services/address.ts delete mode 100644 packages/cart/src/services/cart.ts delete mode 100644 packages/cart/src/services/line-item-adjustment.ts delete mode 100644 packages/cart/src/services/line-item-tax-line.ts delete mode 100644 packages/cart/src/services/line-item.ts delete mode 100644 packages/cart/src/services/shipping-method-adjustment.ts delete mode 100644 packages/cart/src/services/shipping-method-tax-line.ts delete mode 100644 packages/cart/src/services/shipping-method.ts delete mode 100644 packages/cart/src/types/repositories.ts delete mode 100644 packages/customer/src/services/address.ts delete mode 100644 packages/customer/src/services/customer-group-customer.ts delete mode 100644 packages/customer/src/services/customer-group.ts delete mode 100644 packages/customer/src/services/customer.ts rename packages/customer/src/types/{ => services}/address.ts (100%) create mode 100644 packages/customer/src/types/services/customer-group-customer.ts create mode 100644 packages/customer/src/types/services/index.ts delete mode 100644 packages/payment/src/services/payment-collection.ts delete mode 100644 packages/payment/src/types/repositories.ts delete mode 100644 packages/pricing/src/services/currency.ts delete mode 100644 packages/pricing/src/services/money-amount.ts delete mode 100644 packages/pricing/src/services/price-set-money-amount-rules.ts delete mode 100644 packages/pricing/src/services/price-set-money-amount.ts delete mode 100644 packages/pricing/src/services/price-set-rule-type.ts delete mode 100644 packages/pricing/src/services/price-set.ts delete mode 100644 packages/product/src/services/product-image.ts delete mode 100644 packages/product/src/services/product-option-value.ts delete mode 100644 packages/product/src/types/repositories.ts delete mode 100644 packages/promotion/src/services/application-method.ts delete mode 100644 packages/promotion/src/services/campaign-budget.ts delete mode 100644 packages/promotion/src/services/campaign.ts delete mode 100644 packages/promotion/src/services/promotion-rule-value.ts delete mode 100644 packages/promotion/src/services/promotion-rule.ts delete mode 100644 packages/promotion/src/services/promotion.ts delete mode 100644 packages/promotion/src/types/repositories.ts delete mode 100644 packages/sales-channel/src/services/sales-channel.ts delete mode 100644 packages/sales-channel/src/types/repositories.ts create mode 100644 packages/types/src/modules-sdk/internal-module-service.ts create mode 100644 packages/types/src/modules-sdk/module-service.ts create mode 100644 packages/utils/src/common/__tests__/pluralize.spec.ts create mode 100644 packages/utils/src/common/plurailze.ts delete mode 100644 packages/utils/src/dal/repository.ts create mode 100644 packages/utils/src/modules-sdk/__tests__/abstract-module-service-factory.spec.ts create mode 100644 packages/utils/src/modules-sdk/__tests__/internal-module-service-factory.spec.ts create mode 100644 packages/utils/src/modules-sdk/abstract-module-service-factory.ts delete mode 100644 packages/utils/src/modules-sdk/abstract-service-factory.ts create mode 100644 packages/utils/src/modules-sdk/internal-module-service-factory.ts delete mode 100644 packages/workflow-engine-inmemory/src/services/workflow-execution.ts delete mode 100644 packages/workflow-engine-redis/src/services/workflow-execution.ts diff --git a/integration-tests/plugins/__tests__/customer/store/list-customer-addresses.ts b/integration-tests/plugins/__tests__/customer/store/list-customer-addresses.ts index abaf5abe24..ca4753eac7 100644 --- a/integration-tests/plugins/__tests__/customer/store/list-customer-addresses.ts +++ b/integration-tests/plugins/__tests__/customer/store/list-customer-addresses.ts @@ -9,6 +9,8 @@ import { createAuthenticatedCustomer } from "../../../helpers/create-authenticat const env = { MEDUSA_FF_MEDUSA_V2: true } +jest.setTimeout(100000) + describe("GET /store/customers/me/addresses", () => { let dbConnection let appContainer @@ -16,13 +18,17 @@ describe("GET /store/customers/me/addresses", () => { let customerModuleService: ICustomerModuleService beforeAll(async () => { - const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) - dbConnection = await initDb({ cwd, env } as any) - shutdownServer = await startBootstrapApp({ cwd, env }) - appContainer = getContainer() - customerModuleService = appContainer.resolve( - ModuleRegistrationName.CUSTOMER - ) + try { + const cwd = path.resolve(path.join(__dirname, "..", "..", "..")) + dbConnection = await initDb({ cwd, env } as any) + shutdownServer = await startBootstrapApp({ cwd, env }) + appContainer = getContainer() + customerModuleService = appContainer.resolve( + ModuleRegistrationName.CUSTOMER + ) + } catch (error) { + console.error(error) + } }) afterAll(async () => { diff --git a/integration-tests/plugins/__tests__/product/admin/create-product-variant.spec.ts b/integration-tests/plugins/__tests__/product/admin/create-product-variant.spec.ts index 51e99ad6ad..3fd7165c48 100644 --- a/integration-tests/plugins/__tests__/product/admin/create-product-variant.spec.ts +++ b/integration-tests/plugins/__tests__/product/admin/create-product-variant.spec.ts @@ -5,14 +5,13 @@ import { simpleProductFactory, simpleRegionFactory, } from "../../../../factories" - -import { PricingModuleService } from "@medusajs/pricing" -import { ProductModuleService } from "@medusajs/product" import { AxiosInstance } from "axios" import path from "path" import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" import adminSeeder from "../../../../helpers/admin-seeder" import { createDefaultRuleTypes } from "../../../helpers/create-default-rule-types" +import { ProductModuleService } from "@medusajs/product" +import { PricingModuleService } from "@medusajs/pricing" jest.setTimeout(50000) diff --git a/integration-tests/plugins/__tests__/workflows/product/create-product.ts b/integration-tests/plugins/__tests__/workflows/product/create-product.ts index 5d218d108e..11de759e37 100644 --- a/integration-tests/plugins/__tests__/workflows/product/create-product.ts +++ b/integration-tests/plugins/__tests__/workflows/product/create-product.ts @@ -11,7 +11,7 @@ import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app import { getContainer } from "../../../../environment-helpers/use-container" import { initDb, useDb } from "../../../../environment-helpers/use-db" -jest.setTimeout(30000) +jest.setTimeout(50000) describe("CreateProduct workflow", function () { let medusaContainer @@ -129,7 +129,7 @@ describe("CreateProduct workflow", function () { expect(product).toEqual( expect.objectContaining({ - deleted_at: expect.any(String), + deleted_at: expect.any(Date), }) ) }) diff --git a/packages/auth/integration-tests/__tests__/services/auth-provider/index.spec.ts b/packages/auth/integration-tests/__tests__/services/auth-provider/index.spec.ts index 934bf94ec7..3ce97ecd45 100644 --- a/packages/auth/integration-tests/__tests__/services/auth-provider/index.spec.ts +++ b/packages/auth/integration-tests/__tests__/services/auth-provider/index.spec.ts @@ -1,16 +1,16 @@ import { SqlEntityManager } from "@mikro-orm/postgresql" -import { AuthProviderService } from "@services" import { MikroOrmWrapper } from "../../../utils" import { createAuthProviders } from "../../../__fixtures__/auth-provider" import { createMedusaContainer } from "@medusajs/utils" import { asValue } from "awilix" import ContainerLoader from "../../../../src/loaders/container" +import { ModulesSdkTypes } from "@medusajs/types" jest.setTimeout(30000) describe("AuthProvider Service", () => { - let service: AuthProviderService + let service: ModulesSdkTypes.InternalModuleService let testManager: SqlEntityManager let repositoryManager: SqlEntityManager @@ -180,7 +180,7 @@ describe("AuthProvider Service", () => { error = e } - expect(error.message).toEqual('"authProviderProvider" must be defined') + expect(error.message).toEqual("authProvider - provider must be defined") }) it("should return authProvider based on config select param", async () => { diff --git a/packages/auth/integration-tests/__tests__/services/auth-user/index.spec.ts b/packages/auth/integration-tests/__tests__/services/auth-user/index.spec.ts index 1737aa19b4..7dd4afe52e 100644 --- a/packages/auth/integration-tests/__tests__/services/auth-user/index.spec.ts +++ b/packages/auth/integration-tests/__tests__/services/auth-user/index.spec.ts @@ -166,7 +166,7 @@ describe("AuthUser Service", () => { error = e } - expect(error.message).toEqual('"authUserId" must be defined') + expect(error.message).toEqual("authUser - id must be defined") }) }) @@ -229,7 +229,7 @@ describe("AuthUser Service", () => { id: "test", provider_id: "manual", entity_id: "test", - scope: "store" + scope: "store", }, ]) diff --git a/packages/auth/integration-tests/__tests__/services/module/auth-provider.spec.ts b/packages/auth/integration-tests/__tests__/services/module/auth-provider.spec.ts index 2fdf373176..37aaa50ad2 100644 --- a/packages/auth/integration-tests/__tests__/services/module/auth-provider.spec.ts +++ b/packages/auth/integration-tests/__tests__/services/module/auth-provider.spec.ts @@ -43,9 +43,8 @@ describe("AuthModuleService - AuthProvider", () => { describe("listAuthProviders", () => { it("should list AuthProviders", async () => { const authProviders = await service.listAuthProviders() - const serialized = JSON.parse(JSON.stringify(authProviders)) - expect(serialized).toEqual( + expect(authProviders).toEqual( expect.arrayContaining([ expect.objectContaining({ provider: "manual", @@ -80,9 +79,7 @@ describe("AuthModuleService - AuthProvider", () => { is_active: true, }) - const serialized = JSON.parse(JSON.stringify(authProviders)) - - expect(serialized).toEqual([ + expect(authProviders).toEqual([ expect.objectContaining({ provider: "manual", }), @@ -99,10 +96,9 @@ describe("AuthModuleService - AuthProvider", () => { describe("listAndCountAuthProviders", () => { it("should list and count AuthProviders", async () => { const [authProviders, count] = await service.listAndCountAuthProviders() - const serialized = JSON.parse(JSON.stringify(authProviders)) expect(count).toEqual(4) - expect(serialized).toEqual([ + expect(authProviders).toEqual([ expect.objectContaining({ provider: "manual", }), @@ -136,10 +132,8 @@ describe("AuthModuleService - AuthProvider", () => { is_active: true, }) - const serialized = JSON.parse(JSON.stringify(authProviders)) - expect(count).toEqual(3) - expect(serialized).toEqual([ + expect(authProviders).toEqual([ expect.objectContaining({ provider: "manual", }), @@ -171,9 +165,7 @@ describe("AuthModuleService - AuthProvider", () => { select: ["provider"], }) - const serialized = JSON.parse(JSON.stringify(authProvider)) - - expect(serialized).toEqual({ + expect(authProvider).toEqual({ provider, }) }) @@ -201,7 +193,7 @@ describe("AuthModuleService - AuthProvider", () => { error = e } - expect(error.message).toEqual('"authProviderProvider" must be defined') + expect(error.message).toEqual("authProvider - provider must be defined") }) }) @@ -209,7 +201,7 @@ describe("AuthModuleService - AuthProvider", () => { const provider = "manual" it("should delete the authProviders given a provider successfully", async () => { - await service.deleteAuthProvider([provider]) + await service.deleteAuthProviders([provider]) const authProviders = await service.listAuthProviders({ provider: [provider], diff --git a/packages/auth/integration-tests/__tests__/services/module/auth-user.spec.ts b/packages/auth/integration-tests/__tests__/services/module/auth-user.spec.ts index 641ee17e1d..3ca27ed83e 100644 --- a/packages/auth/integration-tests/__tests__/services/module/auth-user.spec.ts +++ b/packages/auth/integration-tests/__tests__/services/module/auth-user.spec.ts @@ -43,17 +43,16 @@ describe("AuthModuleService - AuthUser", () => { describe("listAuthUsers", () => { it("should list authUsers", async () => { const authUsers = await service.listAuthUsers() - const serialized = JSON.parse(JSON.stringify(authUsers)) - expect(serialized).toEqual([ + expect(authUsers).toEqual([ expect.objectContaining({ - provider: "manual", + provider: { provider: "manual" }, }), expect.objectContaining({ - provider: "manual", + provider: { provider: "manual" }, }), expect.objectContaining({ - provider: "store", + provider: { provider: "store" }, }), ]) }) @@ -75,9 +74,7 @@ describe("AuthModuleService - AuthUser", () => { provider_id: "manual", }) - const serialized = JSON.parse(JSON.stringify(authUsers)) - - expect(serialized).toEqual([ + expect(authUsers).toEqual([ expect.objectContaining({ id: "test-id", }), @@ -91,18 +88,17 @@ describe("AuthModuleService - AuthUser", () => { describe("listAndCountAuthUsers", () => { it("should list and count authUsers", async () => { const [authUsers, count] = await service.listAndCountAuthUsers() - const serialized = JSON.parse(JSON.stringify(authUsers)) expect(count).toEqual(3) - expect(serialized).toEqual([ + expect(authUsers).toEqual([ expect.objectContaining({ - provider: "manual", + provider: { provider: "manual" }, }), expect.objectContaining({ - provider: "manual", + provider: { provider: "manual" }, }), expect.objectContaining({ - provider: "store", + provider: { provider: "store" }, }), ]) }) @@ -171,7 +167,7 @@ describe("AuthModuleService - AuthUser", () => { error = e } - expect(error.message).toEqual('"authUserId" must be defined') + expect(error.message).toEqual("authUser - id must be defined") }) it("should return authUser based on config select param", async () => { @@ -179,9 +175,7 @@ describe("AuthModuleService - AuthUser", () => { select: ["id"], }) - const serialized = JSON.parse(JSON.stringify(authUser)) - - expect(serialized).toEqual({ + expect(authUser).toEqual({ id, }) }) @@ -191,7 +185,7 @@ describe("AuthModuleService - AuthUser", () => { const id = "test-id" it("should delete the authUsers given an id successfully", async () => { - await service.deleteAuthUser([id]) + await service.deleteAuthUsers([id]) const authUsers = await service.listAuthUsers({ id: [id], diff --git a/packages/auth/integration-tests/__tests__/services/module/providers.spec.ts b/packages/auth/integration-tests/__tests__/services/module/providers.spec.ts index f3b79046f4..b118e54ac0 100644 --- a/packages/auth/integration-tests/__tests__/services/module/providers.spec.ts +++ b/packages/auth/integration-tests/__tests__/services/module/providers.spec.ts @@ -45,9 +45,8 @@ describe("AuthModuleService - AuthProvider", () => { describe("listAuthProviders", () => { it("should list default AuthProviders registered by loaders", async () => { const authProviders = await service.listAuthProviders() - const serialized = JSON.parse(JSON.stringify(authProviders)) - expect(serialized).toEqual( + expect(authProviders).toEqual( expect.arrayContaining([ expect.objectContaining({ provider: "emailpass", diff --git a/packages/auth/src/providers/google.ts b/packages/auth/src/providers/google.ts index b5558216e1..77f7d9d878 100644 --- a/packages/auth/src/providers/google.ts +++ b/packages/auth/src/providers/google.ts @@ -1,10 +1,11 @@ import { AbstractAuthModuleProvider, MedusaError } from "@medusajs/utils" import { - AuthProviderScope, AuthenticationInput, AuthenticationResponse, + AuthProviderScope, + ModulesSdkTypes, } from "@medusajs/types" -import { AuthProviderService, AuthUserService } from "@services" +import { AuthUserService } from "@services" import jwt, { JwtPayload } from "jsonwebtoken" import { AuthorizationCode } from "simple-oauth2" @@ -12,7 +13,7 @@ import url from "url" type InjectedDependencies = { authUserService: AuthUserService - authProviderService: AuthProviderService + authProviderService: ModulesSdkTypes.InternalModuleService } type ProviderConfig = { @@ -25,13 +26,13 @@ class GoogleProvider extends AbstractAuthModuleProvider { public static PROVIDER = "google" public static DISPLAY_NAME = "Google Authentication" - protected readonly authUserSerivce_: AuthUserService - protected readonly authProviderService_: AuthProviderService + protected readonly authUserService_: AuthUserService + protected readonly authProviderService_: ModulesSdkTypes.InternalModuleService constructor({ authUserService, authProviderService }: InjectedDependencies) { super(arguments[0]) - this.authUserSerivce_ = authUserService + this.authUserService_ = authUserService this.authProviderService_ = authProviderService } @@ -89,13 +90,13 @@ class GoogleProvider extends AbstractAuthModuleProvider { let authUser try { - authUser = await this.authUserSerivce_.retrieveByProviderAndEntityId( + authUser = await this.authUserService_.retrieveByProviderAndEntityId( entity_id, GoogleProvider.PROVIDER ) } catch (error) { if (error.type === MedusaError.Types.NOT_FOUND) { - const [createdAuthUser] = await this.authUserSerivce_.create([ + const [createdAuthUser] = await this.authUserService_.create([ { entity_id, provider: GoogleProvider.PROVIDER, diff --git a/packages/auth/src/services/auth-module.ts b/packages/auth/src/services/auth-module.ts index 34ac05f0dd..995ec3b734 100644 --- a/packages/auth/src/services/auth-module.ts +++ b/packages/auth/src/services/auth-module.ts @@ -1,35 +1,35 @@ import jwt from "jsonwebtoken" import { + AuthenticationInput, + AuthenticationResponse, AuthProviderDTO, AuthTypes, AuthUserDTO, - AuthenticationInput, - AuthenticationResponse, Context, CreateAuthProviderDTO, CreateAuthUserDTO, DAL, - FilterableAuthProviderProps, - FilterableAuthUserProps, - FindConfig, InternalModuleDeclaration, JWTGenerationOptions, - MedusaContainer, ModuleJoinerConfig, + ModulesSdkTypes, UpdateAuthUserDTO, } from "@medusajs/types" + +import { AuthProvider, AuthUser } from "@models" + +import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" + import { AbstractAuthModuleProvider, InjectManager, InjectTransactionManager, MedusaContext, MedusaError, + ModulesSdkUtils, } from "@medusajs/utils" -import { AuthProvider, AuthUser } from "@models" -import { AuthProviderService, AuthUserService } from "@services" import { ServiceTypes } from "@types" -import { joinerConfig } from "../joiner-config" type AuthModuleOptions = { jwt_secret: string @@ -42,28 +42,32 @@ type AuthJWTPayload = { type InjectedDependencies = { baseRepository: DAL.RepositoryService - authUserService: AuthUserService - authProviderService: AuthProviderService + authUserService: ModulesSdkTypes.InternalModuleService + authProviderService: ModulesSdkTypes.InternalModuleService } -export default class AuthModuleService< - TAuthUser extends AuthUser = AuthUser, - TAuthProvider extends AuthProvider = AuthProvider -> implements AuthTypes.IAuthModuleService -{ - __joinerConfig(): ModuleJoinerConfig { - return joinerConfig - } +const generateMethodForModels = [AuthProvider, AuthUser] +export default class AuthModuleService< + TAuthUser extends AuthUser = AuthUser, + TAuthProvider extends AuthProvider = AuthProvider + > + extends ModulesSdkUtils.abstractModuleServiceFactory< + InjectedDependencies, + AuthTypes.AuthProviderDTO, + { + AuthUser: { dto: AuthUserDTO } + AuthProvider: { dto: AuthProviderDTO } + } + >(AuthProvider, generateMethodForModels, entityNameToLinkableKeysMap) + implements AuthTypes.IAuthModuleService +{ __hooks = { onApplicationStart: async () => await this.createProvidersOnLoad(), } - - protected __container__: MedusaContainer protected baseRepository_: DAL.RepositoryService - - protected authUserService_: AuthUserService - protected authProviderService_: AuthProviderService + protected authUserService_: ModulesSdkTypes.InternalModuleService + protected authProviderService_: ModulesSdkTypes.InternalModuleService protected options_: AuthModuleOptions constructor( @@ -75,66 +79,17 @@ export default class AuthModuleService< options: AuthModuleOptions, protected readonly moduleDeclaration: InternalModuleDeclaration ) { - this.__container__ = arguments[0] + // @ts-ignore + super(...arguments) + this.baseRepository_ = baseRepository this.authUserService_ = authUserService this.authProviderService_ = authProviderService this.options_ = options } - async retrieveAuthProvider( - provider: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const authProvider = await this.authProviderService_.retrieve( - provider, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - authProvider, - { populate: true } - ) - } - - async listAuthProviders( - filters: FilterableAuthProviderProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const authProviders = await this.authProviderService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - authProviders, - { populate: true } - ) - } - - @InjectManager("baseRepository_") - async listAndCountAuthProviders( - filters: FilterableAuthProviderProps = {}, - config: FindConfig, - @MedusaContext() sharedContext: Context = {} - ): Promise<[AuthTypes.AuthProviderDTO[], number]> { - const [authProviders, count] = await this.authProviderService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - authProviders, - { populate: true } - ), - count, - ] + __joinerConfig(): ModuleJoinerConfig { + return joinerConfig } async generateJwtToken( @@ -205,18 +160,11 @@ export default class AuthModuleService< return Array.isArray(data) ? serializedProviders : serializedProviders[0] } - @InjectTransactionManager("baseRepository_") - protected async createAuthProviders_( - data: any[], - @MedusaContext() sharedContext: Context - ): Promise { - return await this.authProviderService_.create(data, sharedContext) - } - updateAuthProvider( data: AuthTypes.UpdateAuthProviderDTO[], sharedContext?: Context ): Promise + updateAuthProvider( data: AuthTypes.UpdateAuthProviderDTO, sharedContext?: Context @@ -247,78 +195,11 @@ export default class AuthModuleService< return await this.authProviderService_.update(data, sharedContext) } - @InjectTransactionManager("baseRepository_") - async deleteAuthProvider( - ids: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.authProviderService_.delete(ids, sharedContext) - } - - @InjectManager("baseRepository_") - async retrieveAuthUser( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const authUser = await this.authUserService_.retrieve( - id, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - authUser, - { - exclude: ["password_hash"], - } - ) - } - - @InjectManager("baseRepository_") - async listAuthUsers( - filters: FilterableAuthUserProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const authUsers = await this.authUserService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - authUsers, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCountAuthUsers( - filters: FilterableAuthUserProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[AuthUserDTO[], number]> { - const [authUsers, count] = await this.authUserService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize(authUsers, { - populate: true, - }), - count, - ] - } - createAuthUser( data: CreateAuthUserDTO[], sharedContext?: Context ): Promise + createAuthUser( data: CreateAuthUserDTO, sharedContext?: Context @@ -342,23 +223,17 @@ export default class AuthModuleService< return Array.isArray(data) ? serializedUsers : serializedUsers[0] } - @InjectTransactionManager("baseRepository_") - protected async createAuthUsers_( - data: CreateAuthUserDTO[], - @MedusaContext() sharedContext: Context - ): Promise { - return await this.authUserService_.create(data, sharedContext) - } - updateAuthUser( data: UpdateAuthUserDTO[], sharedContext?: Context ): Promise + updateAuthUser( data: UpdateAuthUserDTO, sharedContext?: Context ): Promise + // TODO: should be pluralized, see convention about the methods naming or the abstract module service interface definition @engineering @InjectManager("baseRepository_") async updateAuthUser( data: UpdateAuthUserDTO | UpdateAuthUserDTO[], @@ -385,14 +260,6 @@ export default class AuthModuleService< return await this.authUserService_.update(data, sharedContext) } - @InjectTransactionManager("baseRepository_") - async deleteAuthUser( - ids: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.authUserService_.delete(ids, sharedContext) - } - protected getRegisteredAuthenticationProvider( provider: string, { authScope }: AuthenticationInput @@ -448,6 +315,22 @@ export default class AuthModuleService< } } + @InjectTransactionManager("baseRepository_") + protected async createAuthProviders_( + data: any[], + @MedusaContext() sharedContext: Context + ): Promise { + return await this.authProviderService_.create(data, sharedContext) + } + + @InjectTransactionManager("baseRepository_") + protected async createAuthUsers_( + data: CreateAuthUserDTO[], + @MedusaContext() sharedContext: Context + ): Promise { + return await this.authUserService_.create(data, sharedContext) + } + private async createProvidersOnLoad() { const providersToLoad = this.__container__["auth_providers"] diff --git a/packages/auth/src/services/auth-provider.ts b/packages/auth/src/services/auth-provider.ts deleted file mode 100644 index 241fb56e80..0000000000 --- a/packages/auth/src/services/auth-provider.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { AuthProvider } from "@models" - -import { ServiceTypes } from "@types" - -type InjectedDependencies = { - authProviderRepository: DAL.RepositoryService -} - -export default class AuthProviderService< - TEntity extends AuthProvider = AuthProvider -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ServiceTypes.CreateAuthProviderDTO - update: ServiceTypes.UpdateAuthProviderDTO - } ->(AuthProvider) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/auth/src/services/auth-user.ts b/packages/auth/src/services/auth-user.ts index 7625415da9..a8e6fcc264 100644 --- a/packages/auth/src/services/auth-user.ts +++ b/packages/auth/src/services/auth-user.ts @@ -1,4 +1,10 @@ -import { AuthTypes, Context, DAL, FindConfig } from "@medusajs/types" +import { + AuthTypes, + Context, + DAL, + FindConfig, + RepositoryService, +} from "@medusajs/types" import { InjectManager, MedusaContext, @@ -6,7 +12,6 @@ import { ModulesSdkUtils, } from "@medusajs/utils" import { AuthUser } from "@models" -import { ServiceTypes, RepositoryTypes } from "@types" type InjectedDependencies = { authUserRepository: DAL.RepositoryService @@ -14,13 +19,11 @@ type InjectedDependencies = { export default class AuthUserService< TEntity extends AuthUser = AuthUser -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ServiceTypes.CreateAuthUserDTO - } ->(AuthUser) { - protected readonly authUserRepository_: RepositoryTypes.IAuthUserRepository +> extends ModulesSdkUtils.internalModuleServiceFactory( + AuthUser +) { + protected readonly authUserRepository_: RepositoryService + constructor(container: InjectedDependencies) { // @ts-ignore super(...arguments) @@ -28,9 +31,7 @@ export default class AuthUserService< } @InjectManager("authUserRepository_") - async retrieveByProviderAndEntityId< - TEntityMethod = AuthTypes.AuthUserDTO - >( + async retrieveByProviderAndEntityId( entityId: string, provider: string, config: FindConfig = {}, diff --git a/packages/auth/src/services/index.ts b/packages/auth/src/services/index.ts index 03a3c0933d..547d1a5466 100644 --- a/packages/auth/src/services/index.ts +++ b/packages/auth/src/services/index.ts @@ -1,3 +1,2 @@ export { default as AuthModuleService } from "./auth-module" -export { default as AuthProviderService } from "./auth-provider" export { default as AuthUserService } from "./auth-user" diff --git a/packages/auth/src/types/repositories/index.ts b/packages/auth/src/types/repositories/index.ts index 86ed738257..b4282c985c 100644 --- a/packages/auth/src/types/repositories/index.ts +++ b/packages/auth/src/types/repositories/index.ts @@ -1,28 +1,2 @@ -import { AuthProvider, AuthUser } from "@models" -import { CreateAuthProviderDTO, UpdateAuthProviderDTO } from "./auth-provider" -import { DAL } from "@medusajs/types" -import { CreateAuthUserDTO, UpdateAuthUserDTO } from "./auth-user" - export * from "./auth-user" export * from "./auth-provider" - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IAuthProviderRepository< - TEntity extends AuthProvider = AuthProvider -> extends DAL.RepositoryService< - TEntity, - { - create: CreateAuthProviderDTO - update: UpdateAuthProviderDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IAuthUserRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreateAuthUserDTO - update: UpdateAuthUserDTO - } - > {} diff --git a/packages/cart/src/services/address.ts b/packages/cart/src/services/address.ts deleted file mode 100644 index 383a07707b..0000000000 --- a/packages/cart/src/services/address.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { Address } from "@models" -import { CreateAddressDTO, UpdateAddressDTO } from "@types" - -type InjectedDependencies = { - addressRepository: DAL.RepositoryService -} - -export default class AddressService< - TEntity extends Address = Address -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateAddressDTO - update: UpdateAddressDTO - } ->(Address) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/cart/src/services/cart-module.ts b/packages/cart/src/services/cart-module.ts index e3eaff368a..79274eed6b 100644 --- a/packages/cart/src/services/cart-module.ts +++ b/packages/cart/src/services/cart-module.ts @@ -3,20 +3,22 @@ import { Context, DAL, FilterableLineItemTaxLineProps, - FindConfig, ICartModuleService, InternalModuleDeclaration, ModuleJoinerConfig, + ModulesSdkTypes, } from "@medusajs/types" import { InjectManager, InjectTransactionManager, - MedusaContext, - MedusaError, isObject, isString, + MedusaContext, + MedusaError, + ModulesSdkUtils, } from "@medusajs/utils" import { + Address, Cart, LineItem, LineItemAdjustment, @@ -25,32 +27,73 @@ import { ShippingMethodAdjustment, ShippingMethodTaxLine, } from "@models" -import { CreateLineItemDTO, UpdateLineItemDTO } from "@types" -import { joinerConfig } from "../joiner-config" -import * as services from "../services" +import { + CreateLineItemDTO, + CreateLineItemTaxLineDTO, + CreateShippingMethodDTO, + CreateShippingMethodTaxLineDTO, + UpdateLineItemDTO, + UpdateLineItemTaxLineDTO, + UpdateShippingMethodTaxLineDTO, +} from "@types" +import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" type InjectedDependencies = { baseRepository: DAL.RepositoryService - cartService: services.CartService - addressService: services.AddressService - lineItemService: services.LineItemService - shippingMethodAdjustmentService: services.ShippingMethodAdjustmentService - shippingMethodService: services.ShippingMethodService - lineItemAdjustmentService: services.LineItemAdjustmentService - lineItemTaxLineService: services.LineItemTaxLineService - shippingMethodTaxLineService: services.ShippingMethodTaxLineService + cartService: ModulesSdkTypes.InternalModuleService + addressService: ModulesSdkTypes.InternalModuleService + lineItemService: ModulesSdkTypes.InternalModuleService + shippingMethodAdjustmentService: ModulesSdkTypes.InternalModuleService + shippingMethodService: ModulesSdkTypes.InternalModuleService + lineItemAdjustmentService: ModulesSdkTypes.InternalModuleService + lineItemTaxLineService: ModulesSdkTypes.InternalModuleService + shippingMethodTaxLineService: ModulesSdkTypes.InternalModuleService } -export default class CartModuleService implements ICartModuleService { +const generateMethodForModels = [ + Address, + LineItem, + LineItemAdjustment, + LineItemTaxLine, + ShippingMethod, + ShippingMethodAdjustment, + ShippingMethodTaxLine, +] + +export default class CartModuleService< + TCart extends Cart = Cart, + TAddress extends Address = Address, + TLineItem extends LineItem = LineItem, + TLineItemAdjustment extends LineItemAdjustment = LineItemAdjustment, + TLineItemTaxLine extends LineItemTaxLine = LineItemTaxLine, + TShippingMethodAdjustment extends ShippingMethodAdjustment = ShippingMethodAdjustment, + TShippingMethodTaxLine extends ShippingMethodTaxLine = ShippingMethodTaxLine, + TShippingMethod extends ShippingMethod = ShippingMethod + > + extends ModulesSdkUtils.abstractModuleServiceFactory< + InjectedDependencies, + CartTypes.CartDTO, + { + Address: { dto: CartTypes.CartAddressDTO } + LineItem: { dto: CartTypes.CartLineItemDTO } + LineItemAdjustment: { dto: CartTypes.LineItemAdjustmentDTO } + LineItemTaxLine: { dto: CartTypes.LineItemTaxLineDTO } + ShippingMethod: { dto: CartTypes.CartShippingMethodDTO } + ShippingMethodAdjustment: { dto: CartTypes.ShippingMethodAdjustmentDTO } + ShippingMethodTaxLine: { dto: CartTypes.ShippingMethodTaxLineDTO } + } + >(Cart, generateMethodForModels, entityNameToLinkableKeysMap) + implements ICartModuleService +{ protected baseRepository_: DAL.RepositoryService - protected cartService_: services.CartService - protected addressService_: services.AddressService - protected lineItemService_: services.LineItemService - protected shippingMethodAdjustmentService_: services.ShippingMethodAdjustmentService - protected shippingMethodService_: services.ShippingMethodService - protected lineItemAdjustmentService_: services.LineItemAdjustmentService - protected lineItemTaxLineService_: services.LineItemTaxLineService - protected shippingMethodTaxLineService_: services.ShippingMethodTaxLineService + protected cartService_: ModulesSdkTypes.InternalModuleService + protected addressService_: ModulesSdkTypes.InternalModuleService + protected lineItemService_: ModulesSdkTypes.InternalModuleService + protected shippingMethodAdjustmentService_: ModulesSdkTypes.InternalModuleService + protected shippingMethodService_: ModulesSdkTypes.InternalModuleService + protected lineItemAdjustmentService_: ModulesSdkTypes.InternalModuleService + protected lineItemTaxLineService_: ModulesSdkTypes.InternalModuleService + protected shippingMethodTaxLineService_: ModulesSdkTypes.InternalModuleService constructor( { @@ -66,6 +109,9 @@ export default class CartModuleService implements ICartModuleService { }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { + // @ts-ignore + super(...arguments) + this.baseRepository_ = baseRepository this.cartService_ = cartService this.addressService_ = addressService @@ -81,52 +127,6 @@ export default class CartModuleService implements ICartModuleService { return joinerConfig } - @InjectManager("baseRepository_") - async retrieve( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const cart = await this.cartService_.retrieve(id, config, sharedContext) - - return await this.baseRepository_.serialize(cart, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async list( - filters: CartTypes.FilterableCartProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const carts = await this.cartService_.list(filters, config, sharedContext) - - return this.baseRepository_.serialize(carts, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async listAndCount( - filters: CartTypes.FilterableCartProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[CartTypes.CartDTO[], number]> { - const [carts, count] = await this.cartService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize(carts, { - populate: true, - }), - count, - ] - } - async create( data: CartTypes.CreateCartDTO[], sharedContext?: Context @@ -229,98 +229,6 @@ export default class CartModuleService implements ICartModuleService { return await this.cartService_.update(data, sharedContext) } - async delete(ids: string[], sharedContext?: Context): Promise - - async delete(ids: string, sharedContext?: Context): Promise - - @InjectTransactionManager("baseRepository_") - async delete( - ids: string[] | string, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const cartIds = Array.isArray(ids) ? ids : [ids] - await this.cartService_.delete(cartIds, sharedContext) - } - - @InjectManager("baseRepository_") - async listAddresses( - filters: CartTypes.FilterableAddressProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const addresses = await this.addressService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - addresses, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async retrieveLineItem( - itemId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const item = await this.lineItemService_.retrieve( - itemId, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - item, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listLineItems( - filters: CartTypes.FilterableLineItemProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const items = await this.lineItemService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - items, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listShippingMethods( - filters: CartTypes.FilterableShippingMethodProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const methods = await this.shippingMethodService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize< - CartTypes.CartShippingMethodDTO[] - >(methods, { - populate: true, - }) - } - addLineItems( data: CartTypes.CreateLineItemForCartDTO ): Promise @@ -585,18 +493,6 @@ export default class CartModuleService implements ICartModuleService { return await this.addressService_.update(data, sharedContext) } - async deleteAddresses(ids: string[], sharedContext?: Context): Promise - async deleteAddresses(ids: string, sharedContext?: Context): Promise - - @InjectTransactionManager("baseRepository_") - async deleteAddresses( - ids: string[] | string, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const addressIds = Array.isArray(ids) ? ids : [ids] - await this.addressService_.delete(addressIds, sharedContext) - } - async addShippingMethods( data: CartTypes.CreateShippingMethodDTO ): Promise @@ -665,7 +561,10 @@ export default class CartModuleService implements ICartModuleService { data: CartTypes.CreateShippingMethodDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { - return await this.shippingMethodService_.create(data, sharedContext) + return await this.shippingMethodService_.create( + data as unknown as CreateShippingMethodDTO[], + sharedContext + ) } async removeShippingMethods( @@ -708,25 +607,6 @@ export default class CartModuleService implements ICartModuleService { await this.shippingMethodService_.delete(toDelete, sharedContext) } - @InjectManager("baseRepository_") - async listLineItemAdjustments( - filters: CartTypes.FilterableLineItemAdjustmentProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const adjustments = await this.lineItemAdjustmentService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize< - CartTypes.LineItemAdjustmentDTO[] - >(adjustments, { - populate: true, - }) - } - async addLineItemAdjustments( adjustments: CartTypes.CreateLineItemAdjustmentDTO[] ): Promise @@ -882,25 +762,6 @@ export default class CartModuleService implements ICartModuleService { await this.lineItemAdjustmentService_.delete(ids, sharedContext) } - @InjectManager("baseRepository_") - async listShippingMethodAdjustments( - filters: CartTypes.FilterableShippingMethodAdjustmentProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const adjustments = await this.shippingMethodAdjustmentService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize< - CartTypes.ShippingMethodAdjustmentDTO[] - >(adjustments, { - populate: true, - }) - } - @InjectTransactionManager("baseRepository_") async setShippingMethodAdjustments( cartId: string, @@ -1070,26 +931,6 @@ export default class CartModuleService implements ICartModuleService { await this.shippingMethodAdjustmentService_.delete(ids, sharedContext) } - @InjectManager("baseRepository_") - async listLineItemTaxLines( - filters: CartTypes.FilterableLineItemTaxLineProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const taxLines = await this.lineItemTaxLineService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - taxLines, - { - populate: true, - } - ) - } - addLineItemTaxLines( taxLines: CartTypes.CreateLineItemTaxLineDTO[] ): Promise @@ -1123,14 +964,14 @@ export default class CartModuleService implements ICartModuleService { const lines = Array.isArray(taxLines) ? taxLines : [taxLines] addedTaxLines = await this.lineItemTaxLineService_.create( - lines as CartTypes.CreateLineItemTaxLineDTO[], + lines as CreateLineItemTaxLineDTO[], sharedContext ) } else { const data = Array.isArray(cartIdOrData) ? cartIdOrData : [cartIdOrData] addedTaxLines = await this.lineItemTaxLineService_.create( - data as CartTypes.CreateLineItemTaxLineDTO[], + data as CreateLineItemTaxLineDTO[], sharedContext ) } @@ -1184,13 +1025,15 @@ export default class CartModuleService implements ICartModuleService { } }) - await this.lineItemTaxLineService_.delete( - toDelete.map((taxLine) => taxLine!.id), - sharedContext - ) + if (toDelete.length) { + await this.lineItemTaxLineService_.delete( + toDelete.map((taxLine) => taxLine!.id), + sharedContext + ) + } const result = await this.lineItemTaxLineService_.upsert( - taxLines, + taxLines as UpdateLineItemTaxLineDTO[], sharedContext ) @@ -1242,25 +1085,6 @@ export default class CartModuleService implements ICartModuleService { await this.lineItemTaxLineService_.delete(ids, sharedContext) } - @InjectManager("baseRepository_") - async listShippingMethodTaxLines( - filters: CartTypes.FilterableShippingMethodTaxLineProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const taxLines = await this.shippingMethodTaxLineService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize< - CartTypes.ShippingMethodTaxLineDTO[] - >(taxLines, { - populate: true, - }) - } - addShippingMethodTaxLines( taxLines: CartTypes.CreateShippingMethodTaxLineDTO[] ): Promise @@ -1296,12 +1120,12 @@ export default class CartModuleService implements ICartModuleService { const lines = Array.isArray(taxLines) ? taxLines : [taxLines] addedTaxLines = await this.shippingMethodTaxLineService_.create( - lines as CartTypes.CreateShippingMethodTaxLineDTO[], + lines as CreateShippingMethodTaxLineDTO[], sharedContext ) } else { addedTaxLines = await this.shippingMethodTaxLineService_.create( - taxLines as CartTypes.CreateShippingMethodTaxLineDTO[], + taxLines as CreateShippingMethodTaxLineDTO[], sharedContext ) } @@ -1367,7 +1191,7 @@ export default class CartModuleService implements ICartModuleService { } const result = await this.shippingMethodTaxLineService_.upsert( - taxLines, + taxLines as UpdateShippingMethodTaxLineDTO[], sharedContext ) diff --git a/packages/cart/src/services/cart.ts b/packages/cart/src/services/cart.ts deleted file mode 100644 index a9c594555b..0000000000 --- a/packages/cart/src/services/cart.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { Cart } from "@models" -import { CreateCartDTO, UpdateCartDTO } from "@types" - -type InjectedDependencies = { - cartRepository: DAL.RepositoryService -} - -export default class CartService< - TEntity extends Cart = Cart -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateCartDTO - update: UpdateCartDTO - } ->(Cart) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/cart/src/services/index.ts b/packages/cart/src/services/index.ts index 7120b701d7..2ed2053ffc 100644 --- a/packages/cart/src/services/index.ts +++ b/packages/cart/src/services/index.ts @@ -1,10 +1 @@ -export { default as AddressService } from "./address" -export { default as CartService } from "./cart" export { default as CartModuleService } from "./cart-module" -export { default as LineItemService } from "./line-item" -export { default as LineItemAdjustmentService } from "./line-item-adjustment" -export { default as LineItemTaxLineService } from "./line-item-tax-line" -export { default as ShippingMethodService } from "./shipping-method" -export { default as ShippingMethodAdjustmentService } from "./shipping-method-adjustment" -export { default as ShippingMethodTaxLineService } from "./shipping-method-tax-line" - diff --git a/packages/cart/src/services/line-item-adjustment.ts b/packages/cart/src/services/line-item-adjustment.ts deleted file mode 100644 index 9ee93b2d95..0000000000 --- a/packages/cart/src/services/line-item-adjustment.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { LineItemAdjustment } from "@models" -import { - CreateLineItemAdjustmentDTO, - UpdateLineItemAdjustmentDTO, -} from "@types" - -type InjectedDependencies = { - lineItemAdjustmentRepository: DAL.RepositoryService -} - -export default class LineItemAdjustmentService< - TEntity extends LineItemAdjustment = LineItemAdjustment -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateLineItemAdjustmentDTO - update: UpdateLineItemAdjustmentDTO - } ->(LineItemAdjustment) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/cart/src/services/line-item-tax-line.ts b/packages/cart/src/services/line-item-tax-line.ts deleted file mode 100644 index a740fae436..0000000000 --- a/packages/cart/src/services/line-item-tax-line.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { - CreateLineItemTaxLineDTO, - DAL, - UpdateLineItemTaxLineDTO, -} from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { LineItemTaxLine } from "@models" - -type InjectedDependencies = { - lineItemTaxLineRepository: DAL.RepositoryService -} - -export default class LineItemTaxLineService< - TEntity extends LineItemTaxLine = LineItemTaxLine -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateLineItemTaxLineDTO - update: UpdateLineItemTaxLineDTO - } ->(LineItemTaxLine) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/cart/src/services/line-item.ts b/packages/cart/src/services/line-item.ts deleted file mode 100644 index ec736f4010..0000000000 --- a/packages/cart/src/services/line-item.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { LineItem } from "@models" -import { CreateLineItemDTO, UpdateLineItemDTO } from "@types" - -type InjectedDependencies = { - lineItemRepository: DAL.RepositoryService -} - -export default class LineItemService< - TEntity extends LineItem = LineItem -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateLineItemDTO - update: UpdateLineItemDTO - } ->(LineItem) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/cart/src/services/shipping-method-adjustment.ts b/packages/cart/src/services/shipping-method-adjustment.ts deleted file mode 100644 index 5688cd662b..0000000000 --- a/packages/cart/src/services/shipping-method-adjustment.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { ShippingMethodAdjustment } from "@models" -import { - CreateShippingMethodAdjustmentDTO, - UpdateShippingMethodAdjustmentDTO, -} from "@types" - -type InjectedDependencies = { - shippingMethodAdjustmentRepository: DAL.RepositoryService -} - -export default class ShippingMethodAdjustmentService< - TEntity extends ShippingMethodAdjustment = ShippingMethodAdjustment -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateShippingMethodAdjustmentDTO - update: UpdateShippingMethodAdjustmentDTO - } ->(ShippingMethodAdjustment) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/cart/src/services/shipping-method-tax-line.ts b/packages/cart/src/services/shipping-method-tax-line.ts deleted file mode 100644 index 9229d65567..0000000000 --- a/packages/cart/src/services/shipping-method-tax-line.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { CreateShippingMethodTaxLineDTO, DAL, UpdateShippingMethodTaxLineDTO } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { ShippingMethodTaxLine } from "@models" - -type InjectedDependencies = { - shippingMethodTaxLineRepository: DAL.RepositoryService -} - -export default class ShippingMethodTaxLineService< - TEntity extends ShippingMethodTaxLine = ShippingMethodTaxLine -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateShippingMethodTaxLineDTO - update: UpdateShippingMethodTaxLineDTO - } ->(ShippingMethodTaxLine) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/cart/src/services/shipping-method.ts b/packages/cart/src/services/shipping-method.ts deleted file mode 100644 index f3cf667144..0000000000 --- a/packages/cart/src/services/shipping-method.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { ShippingMethod } from "@models" -import { CreateShippingMethodDTO, UpdateShippingMethodDTO } from "../types" - -type InjectedDependencies = { - shippingMethodRepository: DAL.RepositoryService -} - -export default class ShippingMethodService< - TEntity extends ShippingMethod = ShippingMethod -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateShippingMethodDTO - update: UpdateShippingMethodDTO - } ->(ShippingMethod) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/cart/src/types/index.ts b/packages/cart/src/types/index.ts index 03f39f0916..9e420fcb7f 100644 --- a/packages/cart/src/types/index.ts +++ b/packages/cart/src/types/index.ts @@ -5,7 +5,6 @@ export * from "./cart" export * from "./line-item" export * from "./line-item-adjustment" export * from "./line-item-tax-line" -export * from "./repositories" export * from "./shipping-method" export * from "./shipping-method-adjustment" export * from "./shipping-method-tax-line" diff --git a/packages/cart/src/types/repositories.ts b/packages/cart/src/types/repositories.ts deleted file mode 100644 index 3d028f6c8e..0000000000 --- a/packages/cart/src/types/repositories.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { DAL } from "@medusajs/types" -import { - Cart, - LineItem, - LineItemAdjustment, - LineItemTaxLine, - ShippingMethod, - ShippingMethodAdjustment, - ShippingMethodTaxLine, -} from "@models" -import { CreateAddressDTO, UpdateAddressDTO } from "./address" -import { CreateCartDTO, UpdateCartDTO } from "./cart" -import { CreateLineItemDTO, UpdateLineItemDTO } from "./line-item" -import { - CreateLineItemAdjustmentDTO, - UpdateLineItemAdjustmentDTO, -} from "./line-item-adjustment" -import { - CreateLineItemTaxLineDTO, - UpdateLineItemTaxLineDTO, -} from "./line-item-tax-line" -import { - CreateShippingMethodDTO, - UpdateShippingMethodDTO, -} from "./shipping-method" -import { - CreateShippingMethodAdjustmentDTO, - UpdateShippingMethodAdjustmentDTO, -} from "./shipping-method-adjustment" -import { - CreateShippingMethodTaxLineDTO, - UpdateShippingMethodTaxLineDTO, -} from "./shipping-method-tax-line" - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IAddressRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreateAddressDTO - update: UpdateAddressDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ICartRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreateCartDTO - update: UpdateCartDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ILineItemRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreateLineItemDTO - update: UpdateLineItemDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IShippingMethodRepository< - TEntity extends ShippingMethod = ShippingMethod -> extends DAL.RepositoryService< - TEntity, - { - create: CreateShippingMethodDTO - update: UpdateShippingMethodDTO - } - > {} - -export interface ILineItemAdjustmentRepository< - TEntity extends LineItemAdjustment = LineItemAdjustment -> extends DAL.RepositoryService< - TEntity, - { - create: CreateLineItemAdjustmentDTO - update: UpdateLineItemAdjustmentDTO - } - > {} - -export interface IShippingMethodAdjustmentRepository< - TEntity extends ShippingMethodAdjustment = ShippingMethodAdjustment -> extends DAL.RepositoryService< - TEntity, - { - create: CreateShippingMethodAdjustmentDTO - update: UpdateShippingMethodAdjustmentDTO - } - > {} - -export interface IShippingMethodTaxLineRepository< - TEntity extends ShippingMethodTaxLine = ShippingMethodTaxLine -> extends DAL.RepositoryService< - TEntity, - { - create: CreateShippingMethodTaxLineDTO - update: UpdateShippingMethodTaxLineDTO - } - > {} - -export interface ILineItemTaxLineRepository< - TEntity extends LineItemTaxLine = LineItemTaxLine -> extends DAL.RepositoryService< - TEntity, - { - create: CreateLineItemTaxLineDTO - update: UpdateLineItemTaxLineDTO - } - > {} diff --git a/packages/cart/src/types/shipping-method.ts b/packages/cart/src/types/shipping-method.ts index 6e70a4056b..6d15473f1b 100644 --- a/packages/cart/src/types/shipping-method.ts +++ b/packages/cart/src/types/shipping-method.ts @@ -1,6 +1,6 @@ export interface CreateShippingMethodDTO { name: string - cart_id: string + shippingMethod_id: string amount: number data?: Record } diff --git a/packages/core-flows/src/customer-group/steps/delete-customer-groups.ts b/packages/core-flows/src/customer-group/steps/delete-customer-groups.ts index b2b074842c..d9ad730678 100644 --- a/packages/core-flows/src/customer-group/steps/delete-customer-groups.ts +++ b/packages/core-flows/src/customer-group/steps/delete-customer-groups.ts @@ -12,7 +12,7 @@ export const deleteCustomerGroupStep = createStep( ModuleRegistrationName.CUSTOMER ) - await service.softDeleteCustomerGroup(ids) + await service.softDeleteCustomerGroups(ids) return new StepResponse(void 0, ids) }, @@ -25,6 +25,6 @@ export const deleteCustomerGroupStep = createStep( ModuleRegistrationName.CUSTOMER ) - await service.restoreCustomerGroup(prevCustomerGroups) + await service.restoreCustomerGroups(prevCustomerGroups) } ) diff --git a/packages/core-flows/src/customer-group/steps/update-customer-groups.ts b/packages/core-flows/src/customer-group/steps/update-customer-groups.ts index 553f1d5ae6..7acced28eb 100644 --- a/packages/core-flows/src/customer-group/steps/update-customer-groups.ts +++ b/packages/core-flows/src/customer-group/steps/update-customer-groups.ts @@ -1,8 +1,8 @@ import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { + CustomerGroupUpdatableFields, FilterableCustomerGroupProps, ICustomerModuleService, - CustomerGroupUpdatableFields, } from "@medusajs/types" import { getSelectsAndRelationsFromObjectArray, @@ -31,7 +31,7 @@ export const updateCustomerGroupsStep = createStep( relations, }) - const customers = await service.updateCustomerGroup( + const customers = await service.updateCustomerGroups( data.selector, data.update ) @@ -49,7 +49,7 @@ export const updateCustomerGroupsStep = createStep( await promiseAll( prevCustomerGroups.map((c) => - service.updateCustomerGroup(c.id, { + service.updateCustomerGroups(c.id, { name: c.name, }) ) diff --git a/packages/core-flows/src/customer/steps/create-addresses.ts b/packages/core-flows/src/customer/steps/create-addresses.ts index 139aebf0d2..a14686069d 100644 --- a/packages/core-flows/src/customer/steps/create-addresses.ts +++ b/packages/core-flows/src/customer/steps/create-addresses.ts @@ -1,8 +1,8 @@ import { - ICustomerModuleService, CreateCustomerAddressDTO, + ICustomerModuleService, } from "@medusajs/types" -import { StepResponse, createStep } from "@medusajs/workflows-sdk" +import { createStep, StepResponse } from "@medusajs/workflows-sdk" import { ModuleRegistrationName } from "@medusajs/modules-sdk" export const createCustomerAddressesStepId = "create-customer-addresses" @@ -29,6 +29,6 @@ export const createCustomerAddressesStep = createStep( ModuleRegistrationName.CUSTOMER ) - await service.deleteAddress(ids) + await service.deleteAddresses(ids) } ) diff --git a/packages/core-flows/src/customer/steps/delete-addresses.ts b/packages/core-flows/src/customer/steps/delete-addresses.ts index c6ed173299..46bfcab654 100644 --- a/packages/core-flows/src/customer/steps/delete-addresses.ts +++ b/packages/core-flows/src/customer/steps/delete-addresses.ts @@ -14,7 +14,7 @@ export const deleteCustomerAddressesStep = createStep( const existing = await service.listAddresses({ id: ids, }) - await service.deleteAddress(ids) + await service.deleteAddresses(ids) return new StepResponse(void 0, existing) }, diff --git a/packages/core-flows/src/customer/steps/maybe-unset-default-billing-addresses.ts b/packages/core-flows/src/customer/steps/maybe-unset-default-billing-addresses.ts index 50a2b36aca..70212f2c51 100644 --- a/packages/core-flows/src/customer/steps/maybe-unset-default-billing-addresses.ts +++ b/packages/core-flows/src/customer/steps/maybe-unset-default-billing-addresses.ts @@ -1,12 +1,12 @@ import { - ICustomerModuleService, CreateCustomerAddressDTO, - FilterableCustomerAddressProps, CustomerAddressDTO, + FilterableCustomerAddressProps, + ICustomerModuleService, } from "@medusajs/types" import { createStep } from "@medusajs/workflows-sdk" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { unsetForUpdate, unsetForCreate } from "./utils" +import { unsetForCreate, unsetForUpdate } from "./utils" import { isDefined } from "@medusajs/utils" type StepInput = { @@ -53,7 +53,7 @@ export const maybeUnsetDefaultBillingAddressesStep = createStep( ModuleRegistrationName.CUSTOMER ) - await customerModuleService.updateAddress( + await customerModuleService.updateAddresses( { id: addressesToSet }, { is_default_billing: true } ) diff --git a/packages/core-flows/src/customer/steps/maybe-unset-default-shipping-addresses.ts b/packages/core-flows/src/customer/steps/maybe-unset-default-shipping-addresses.ts index 7ffbaf41b0..b484c31a5f 100644 --- a/packages/core-flows/src/customer/steps/maybe-unset-default-shipping-addresses.ts +++ b/packages/core-flows/src/customer/steps/maybe-unset-default-shipping-addresses.ts @@ -1,12 +1,12 @@ import { - ICustomerModuleService, CreateCustomerAddressDTO, - FilterableCustomerAddressProps, CustomerAddressDTO, + FilterableCustomerAddressProps, + ICustomerModuleService, } from "@medusajs/types" import { createStep } from "@medusajs/workflows-sdk" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { unsetForUpdate, unsetForCreate } from "./utils" +import { unsetForCreate, unsetForUpdate } from "./utils" import { isDefined } from "@medusajs/utils" type StepInput = { @@ -52,7 +52,7 @@ export const maybeUnsetDefaultShippingAddressesStep = createStep( ModuleRegistrationName.CUSTOMER ) - await customerModuleService.updateAddress( + await customerModuleService.updateAddresses( { id: addressesToSet }, { is_default_shipping: true } ) diff --git a/packages/core-flows/src/customer/steps/update-addresses.ts b/packages/core-flows/src/customer/steps/update-addresses.ts index 17d7d68be1..49b793e36b 100644 --- a/packages/core-flows/src/customer/steps/update-addresses.ts +++ b/packages/core-flows/src/customer/steps/update-addresses.ts @@ -31,7 +31,7 @@ export const updateCustomerAddressesStep = createStep( relations, }) - const customerAddresses = await service.updateAddress( + const customerAddresses = await service.updateAddresses( data.selector, data.update ) @@ -48,7 +48,7 @@ export const updateCustomerAddressesStep = createStep( ) await promiseAll( - prevCustomerAddresses.map((c) => service.updateAddress(c.id, { ...c })) + prevCustomerAddresses.map((c) => service.updateAddresses(c.id, { ...c })) ) } ) diff --git a/packages/core-flows/src/customer/steps/utils/unset-address-for-create.ts b/packages/core-flows/src/customer/steps/utils/unset-address-for-create.ts index 25c6e15df2..870e67a7a4 100644 --- a/packages/core-flows/src/customer/steps/utils/unset-address-for-create.ts +++ b/packages/core-flows/src/customer/steps/utils/unset-address-for-create.ts @@ -21,7 +21,7 @@ export const unsetForCreate = async ( [field]: true, }) - await customerService.updateAddress( + await customerService.updateAddresses( { customer_id: customerIds, [field]: true }, { [field]: false } ) diff --git a/packages/core-flows/src/customer/steps/utils/unset-address-for-update.ts b/packages/core-flows/src/customer/steps/utils/unset-address-for-update.ts index aa12bb2122..404b550a9c 100644 --- a/packages/core-flows/src/customer/steps/utils/unset-address-for-update.ts +++ b/packages/core-flows/src/customer/steps/utils/unset-address-for-update.ts @@ -28,7 +28,7 @@ export const unsetForUpdate = async ( [field]: true, }) - await customerService.updateAddress( + await customerService.updateAddresses( { customer_id: customerIds, [field]: true }, { [field]: false } ) diff --git a/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts b/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts index 26beb2c4ab..ae5236c734 100644 --- a/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts +++ b/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts @@ -535,7 +535,7 @@ describe("Customer Module Service", () => { await service.delete(customer.id) - const res = await service.listCustomerGroupRelations({ + const res = await service.listCustomerGroupCustomers({ customer_id: customer.id, customer_group_id: group.id, }) @@ -546,7 +546,7 @@ describe("Customer Module Service", () => { describe("deleteCustomerGroup", () => { it("should delete a single customer group", async () => { const [group] = await service.createCustomerGroup([{ name: "VIP" }]) - await service.deleteCustomerGroup(group.id) + await service.deleteCustomerGroups(group.id) await expect( service.retrieveCustomerGroup(group.id) @@ -560,7 +560,7 @@ describe("Customer Module Service", () => { ]) const groupIds = groups.map((group) => group.id) - await service.deleteCustomerGroup(groupIds) + await service.deleteCustomerGroups(groupIds) for (const group of groups) { await expect( @@ -575,7 +575,7 @@ describe("Customer Module Service", () => { await service.createCustomerGroup([{ name: "VIP" }, { name: "Regular" }]) const selector = { name: "VIP" } - await service.deleteCustomerGroup(selector) + await service.deleteCustomerGroups(selector) const remainingGroups = await service.listCustomerGroups({ name: "VIP" }) expect(remainingGroups.length).toBe(0) @@ -595,9 +595,9 @@ describe("Customer Module Service", () => { customer_group_id: group.id, }) - await service.deleteCustomerGroup(group.id) + await service.deleteCustomerGroups(group.id) - const res = await service.listCustomerGroupRelations({ + const res = await service.listCustomerGroupCustomers({ customer_id: customer.id, customer_group_id: group.id, }) @@ -743,7 +743,7 @@ describe("Customer Module Service", () => { address_1: "123 Main St", }) - await service.updateAddress(address.id, { + await service.updateAddresses(address.id, { address_name: "Work", address_1: "456 Main St", }) @@ -778,7 +778,7 @@ describe("Customer Module Service", () => { address_1: "456 Main St", }) - await service.updateAddress( + await service.updateAddresses( { customer_id: customer.id }, { address_name: "Under Construction", @@ -822,7 +822,7 @@ describe("Customer Module Service", () => { }, ]) - await service.updateAddress([address1.id, address2.id], { + await service.updateAddresses([address1.id, address2.id], { address_name: "Under Construction", }) @@ -864,7 +864,7 @@ describe("Customer Module Service", () => { }) await expect( - service.updateAddress(address.id, { is_default_shipping: true }) + service.updateAddresses(address.id, { is_default_shipping: true }) ).rejects.toThrow("A default shipping address already exists") }) }) @@ -1087,7 +1087,7 @@ describe("Customer Module Service", () => { describe("softDeleteCustomerGroup", () => { it("should soft delete a single customer group", async () => { const [group] = await service.createCustomerGroup([{ name: "VIP" }]) - await service.softDeleteCustomerGroup([group.id]) + await service.softDeleteCustomerGroups([group.id]) const res = await service.listCustomerGroups({ id: group.id }) expect(res.length).toBe(0) @@ -1105,7 +1105,7 @@ describe("Customer Module Service", () => { { name: "Regular" }, ]) const groupIds = groups.map((group) => group.id) - await service.softDeleteCustomerGroup(groupIds) + await service.softDeleteCustomerGroups(groupIds) const res = await service.listCustomerGroups({ id: groupIds }) expect(res.length).toBe(0) @@ -1121,12 +1121,12 @@ describe("Customer Module Service", () => { describe("restoreCustomerGroup", () => { it("should restore a single customer group", async () => { const [group] = await service.createCustomerGroup([{ name: "VIP" }]) - await service.softDeleteCustomerGroup([group.id]) + await service.softDeleteCustomerGroups([group.id]) const res = await service.listCustomerGroups({ id: group.id }) expect(res.length).toBe(0) - await service.restoreCustomerGroup([group.id]) + await service.restoreCustomerGroups([group.id]) const restoredGroup = await service.retrieveCustomerGroup(group.id, { withDeleted: true, @@ -1140,12 +1140,12 @@ describe("Customer Module Service", () => { { name: "Regular" }, ]) const groupIds = groups.map((group) => group.id) - await service.softDeleteCustomerGroup(groupIds) + await service.softDeleteCustomerGroups(groupIds) const res = await service.listCustomerGroups({ id: groupIds }) expect(res.length).toBe(0) - await service.restoreCustomerGroup(groupIds) + await service.restoreCustomerGroups(groupIds) const restoredGroups = await service.listCustomerGroups( { id: groupIds }, diff --git a/packages/customer/src/models/address.ts b/packages/customer/src/models/address.ts index 13aacd7c00..817d4c2771 100644 --- a/packages/customer/src/models/address.ts +++ b/packages/customer/src/models/address.ts @@ -2,27 +2,32 @@ import { DAL } from "@medusajs/types" import { generateEntityId } from "@medusajs/utils" import { BeforeCreate, + Cascade, Entity, + Index, + ManyToOne, OnInit, OptionalProps, PrimaryKey, Property, - ManyToOne, - Cascade, - Index, } from "@mikro-orm/core" import Customer from "./customer" type OptionalAddressProps = DAL.EntityDateColumns // TODO: To be revisited when more clear +export const UNIQUE_CUSTOMER_SHIPPING_ADDRESS = + "IDX_customer_address_unique_customer_shipping" +export const UNIQUE_CUSTOMER_BILLING_ADDRESS = + "IDX_customer_address_unique_customer_billing" + @Entity({ tableName: "customer_address" }) @Index({ - name: "IDX_customer_address_unique_customer_shipping", + name: UNIQUE_CUSTOMER_SHIPPING_ADDRESS, expression: 'create unique index "IDX_customer_address_unique_customer_shipping" on "customer_address" ("customer_id") where "is_default_shipping" = true', }) @Index({ - name: "IDX_customer_address_unique_customer_billing", + name: UNIQUE_CUSTOMER_BILLING_ADDRESS, expression: 'create unique index "IDX_customer_address_unique_customer_billing" on "customer_address" ("customer_id") where "is_default_billing" = true', }) diff --git a/packages/customer/src/services/address.ts b/packages/customer/src/services/address.ts deleted file mode 100644 index 383a07707b..0000000000 --- a/packages/customer/src/services/address.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { Address } from "@models" -import { CreateAddressDTO, UpdateAddressDTO } from "@types" - -type InjectedDependencies = { - addressRepository: DAL.RepositoryService -} - -export default class AddressService< - TEntity extends Address = Address -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateAddressDTO - update: UpdateAddressDTO - } ->(Address) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/customer/src/services/customer-group-customer.ts b/packages/customer/src/services/customer-group-customer.ts deleted file mode 100644 index cc61f576af..0000000000 --- a/packages/customer/src/services/customer-group-customer.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { CustomerGroupCustomer } from "@models" - -type CreateCustomerGroupCustomerDTO = { - customer_id: string - customer_group_id: string - created_by?: string -} - -type InjectedDependencies = { - customerGroupRepository: DAL.RepositoryService -} - -export default class CustomerGroupCustomerService< - TEntity extends CustomerGroupCustomer = CustomerGroupCustomer -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { create: CreateCustomerGroupCustomerDTO } ->(CustomerGroupCustomer) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/customer/src/services/customer-group.ts b/packages/customer/src/services/customer-group.ts deleted file mode 100644 index 830e949c58..0000000000 --- a/packages/customer/src/services/customer-group.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { CustomerGroup } from "@models" -import { CreateCustomerGroupDTO, UpdateCustomerGroupDTO } from "@medusajs/types" - -type InjectedDependencies = { - customerGroupRepository: DAL.RepositoryService -} - -export default class CustomerGroupService< - TEntity extends CustomerGroup = CustomerGroup -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateCustomerGroupDTO - update: UpdateCustomerGroupDTO - } ->(CustomerGroup) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/customer/src/services/customer-module.ts b/packages/customer/src/services/customer-module.ts index 7a41d481b8..49b6422e80 100644 --- a/packages/customer/src/services/customer-module.ts +++ b/packages/customer/src/services/customer-module.ts @@ -1,48 +1,69 @@ import { Context, + CustomerDTO, + CustomerTypes, DAL, - FindConfig, ICustomerModuleService, InternalModuleDeclaration, ModuleJoinerConfig, - CustomerTypes, - SoftDeleteReturn, - RestoreReturn, + ModulesSdkTypes, } from "@medusajs/types" import { InjectManager, InjectTransactionManager, - MedusaContext, - mapObjectTo, - isString, - isObject, isDuplicateError, + isString, + MedusaContext, + MedusaError, + ModulesSdkUtils, } from "@medusajs/utils" import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" -import * as services from "../services" -import { MedusaError } from "@medusajs/utils" +import { + Address, + Customer, + CustomerGroup, + CustomerGroupCustomer, +} from "@models" import { EntityManager } from "@mikro-orm/core" - -const UNIQUE_CUSTOMER_SHIPPING_ADDRESS = - "IDX_customer_address_unique_customer_shipping" -const UNIQUE_CUSTOMER_BILLING_ADDRESS = - "IDX_customer_address_unique_customer_billing" +import { + UNIQUE_CUSTOMER_BILLING_ADDRESS, + UNIQUE_CUSTOMER_SHIPPING_ADDRESS, +} from "../models/address" type InjectedDependencies = { baseRepository: DAL.RepositoryService - customerService: services.CustomerService - addressService: services.AddressService - customerGroupService: services.CustomerGroupService - customerGroupCustomerService: services.CustomerGroupCustomerService + customerService: ModulesSdkTypes.InternalModuleService + addressService: ModulesSdkTypes.InternalModuleService + customerGroupService: ModulesSdkTypes.InternalModuleService + customerGroupCustomerService: ModulesSdkTypes.InternalModuleService } -export default class CustomerModuleService implements ICustomerModuleService { +const generateMethodForModels = [Address, CustomerGroup, CustomerGroupCustomer] + +export default class CustomerModuleService< + TAddress extends Address = Address, + TCustomer extends Customer = Customer, + TCustomerGroup extends CustomerGroup = CustomerGroup, + TCustomerGroupCustomer extends CustomerGroupCustomer = CustomerGroupCustomer + > + // TODO seb I let you manage that when you are moving forward + extends ModulesSdkUtils.abstractModuleServiceFactory< + InjectedDependencies, + CustomerDTO, + { + Address: { dto: any } + CustomerGroup: { dto: any } + CustomerGroupCustomer: { dto: any } + } + >(Customer, generateMethodForModels, entityNameToLinkableKeysMap) + implements ICustomerModuleService +{ protected baseRepository_: DAL.RepositoryService - protected customerService_: services.CustomerService - protected addressService_: services.AddressService - protected customerGroupService_: services.CustomerGroupService - protected customerGroupCustomerService_: services.CustomerGroupCustomerService + protected customerService_: ModulesSdkTypes.InternalModuleService + protected addressService_: ModulesSdkTypes.InternalModuleService + protected customerGroupService_: ModulesSdkTypes.InternalModuleService + protected customerGroupCustomerService_: ModulesSdkTypes.InternalModuleService constructor( { @@ -54,6 +75,9 @@ export default class CustomerModuleService implements ICustomerModuleService { }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { + // @ts-ignore + super(...arguments) + this.baseRepository_ = baseRepository this.customerService_ = customerService this.addressService_ = addressService @@ -65,26 +89,6 @@ export default class CustomerModuleService implements ICustomerModuleService { return joinerConfig } - @InjectManager("baseRepository_") - async retrieve( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const customer = await this.customerService_.retrieve( - id, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - customer, - { - populate: true, - } - ) - } - async create( data: CustomerTypes.CreateCustomerDTO, sharedContext?: Context @@ -95,13 +99,33 @@ export default class CustomerModuleService implements ICustomerModuleService { sharedContext?: Context ): Promise - @InjectTransactionManager("baseRepository_") + @InjectManager("baseRepository_") async create( dataOrArray: | CustomerTypes.CreateCustomerDTO | CustomerTypes.CreateCustomerDTO[], @MedusaContext() sharedContext: Context = {} - ) { + ): Promise { + const customers = await this.create_(dataOrArray, sharedContext).catch( + this.handleDbErrors + ) + + const serialized = await this.baseRepository_.serialize< + CustomerTypes.CustomerDTO[] + >(customers, { + populate: true, + }) + + return Array.isArray(dataOrArray) ? serialized : serialized[0] + } + + @InjectTransactionManager("baseRepository_") + async create_( + dataOrArray: + | CustomerTypes.CreateCustomerDTO + | CustomerTypes.CreateCustomerDTO[], + @MedusaContext() sharedContext: Context = {} + ): Promise { const data = Array.isArray(dataOrArray) ? dataOrArray : [dataOrArray] const customers = await this.customerService_.create(data, sharedContext) @@ -121,12 +145,7 @@ export default class CustomerModuleService implements ICustomerModuleService { await this.addAddresses(addressDataWithCustomerIds, sharedContext) - const serialized = await this.baseRepository_.serialize< - CustomerTypes.CustomerDTO[] - >(customers, { - populate: true, - }) - return Array.isArray(dataOrArray) ? serialized : serialized[0] + return customers as unknown as CustomerTypes.CustomerDTO[] } update( @@ -151,37 +170,38 @@ export default class CustomerModuleService implements ICustomerModuleService { data: CustomerTypes.CustomerUpdatableFields, @MedusaContext() sharedContext: Context = {} ) { - let updateData: CustomerTypes.UpdateCustomerDTO[] = [] + let updateData: + | CustomerTypes.UpdateCustomerDTO + | CustomerTypes.UpdateCustomerDTO[] + | { + selector: CustomerTypes.FilterableCustomerProps + data: CustomerTypes.CustomerUpdatableFields + } = [] + if (isString(idsOrSelector)) { - updateData = [ - { - id: idsOrSelector, - ...data, - }, - ] + updateData = { + id: idsOrSelector, + ...data, + } } else if (Array.isArray(idsOrSelector)) { updateData = idsOrSelector.map((id) => ({ id, ...data, })) } else { - const ids = await this.customerService_.list( - idsOrSelector, - { select: ["id"] }, - sharedContext - ) - updateData = ids.map(({ id }) => ({ - id, - ...data, - })) + updateData = { + selector: idsOrSelector, + data: data, + } } const customers = await this.customerService_.update( updateData, sharedContext ) + const serialized = await this.baseRepository_.serialize< - CustomerTypes.CustomerDTO[] + CustomerTypes.CustomerDTO | CustomerTypes.CustomerDTO[] >(customers, { populate: true, }) @@ -189,78 +209,6 @@ export default class CustomerModuleService implements ICustomerModuleService { return isString(idsOrSelector) ? serialized[0] : serialized } - delete(customerId: string, sharedContext?: Context): Promise - delete(customerIds: string[], sharedContext?: Context): Promise - delete( - selector: CustomerTypes.FilterableCustomerProps, - sharedContext?: Context - ): Promise - - @InjectTransactionManager("baseRepository_") - async delete( - idsOrSelector: string | string[] | CustomerTypes.FilterableCustomerProps, - @MedusaContext() sharedContext: Context = {} - ) { - let toDelete = Array.isArray(idsOrSelector) - ? idsOrSelector - : [idsOrSelector as string] - if (isObject(idsOrSelector)) { - const ids = await this.customerService_.list( - idsOrSelector, - { - select: ["id"], - }, - sharedContext - ) - toDelete = ids.map(({ id }) => id) - } - - return await this.customerService_.delete(toDelete, sharedContext) - } - - @InjectManager("baseRepository_") - async list( - filters: CustomerTypes.FilterableCustomerProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const customers = await this.customerService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - customers, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCount( - filters: CustomerTypes.FilterableCustomerProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[CustomerTypes.CustomerDTO[], number]> { - const [customers, count] = await this.customerService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - customers, - { - populate: true, - } - ), - count, - ] - } - async createCustomerGroup( dataOrArrayOfData: CustomerTypes.CreateCustomerGroupDTO, sharedContext?: Context @@ -278,55 +226,36 @@ export default class CustomerModuleService implements ICustomerModuleService { | CustomerTypes.CreateCustomerGroupDTO[], @MedusaContext() sharedContext: Context = {} ) { - const data = Array.isArray(dataOrArrayOfData) - ? dataOrArrayOfData - : [dataOrArrayOfData] + const groups = await this.customerGroupService_.create( + dataOrArrayOfData, + sharedContext + ) - const groups = await this.customerGroupService_.create(data, sharedContext) - const serialized = await this.baseRepository_.serialize< - CustomerTypes.CustomerGroupDTO[] + return await this.baseRepository_.serialize< + CustomerTypes.CustomerGroupDTO | CustomerTypes.CustomerGroupDTO[] >(groups, { populate: true, }) - - return Array.isArray(dataOrArrayOfData) ? serialized : serialized[0] } - @InjectManager("baseRepository_") - async retrieveCustomerGroup( - groupId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const group = await this.customerGroupService_.retrieve( - groupId, - config, - sharedContext - ) - return await this.baseRepository_.serialize( - group, - { populate: true } - ) - } - - async updateCustomerGroup( + async updateCustomerGroups( groupId: string, data: CustomerTypes.CustomerGroupUpdatableFields, sharedContext?: Context ): Promise - async updateCustomerGroup( + async updateCustomerGroups( groupIds: string[], data: CustomerTypes.CustomerGroupUpdatableFields, sharedContext?: Context ): Promise - async updateCustomerGroup( + async updateCustomerGroups( selector: CustomerTypes.FilterableCustomerGroupProps, data: CustomerTypes.CustomerGroupUpdatableFields, sharedContext?: Context ): Promise @InjectTransactionManager("baseRepository_") - async updateCustomerGroup( + async updateCustomerGroups( groupIdOrSelector: | string | string[] @@ -334,29 +263,27 @@ export default class CustomerModuleService implements ICustomerModuleService { data: CustomerTypes.CustomerGroupUpdatableFields, @MedusaContext() sharedContext: Context = {} ) { - let updateData: CustomerTypes.UpdateCustomerGroupDTO[] = [] - if (isString(groupIdOrSelector)) { - updateData = [ - { - id: groupIdOrSelector, - ...data, - }, - ] - } else if (Array.isArray(groupIdOrSelector)) { - updateData = groupIdOrSelector.map((id) => ({ + let updateData: + | CustomerTypes.UpdateCustomerGroupDTO + | CustomerTypes.UpdateCustomerGroupDTO[] + | { + selector: CustomerTypes.FilterableCustomerGroupProps + data: CustomerTypes.CustomerGroupUpdatableFields + } = [] + + if (isString(groupIdOrSelector) || Array.isArray(groupIdOrSelector)) { + const groupIdOrSelectorArray = Array.isArray(groupIdOrSelector) + ? groupIdOrSelector + : [groupIdOrSelector] + updateData = groupIdOrSelectorArray.map((id) => ({ id, ...data, })) } else { - const ids = await this.customerGroupService_.list( - groupIdOrSelector, - { select: ["id"] }, - sharedContext - ) - updateData = ids.map(({ id }) => ({ - id, - ...data, - })) + updateData = { + selector: groupIdOrSelector, + data: data, + } } const groups = await this.customerGroupService_.update( @@ -376,39 +303,6 @@ export default class CustomerModuleService implements ICustomerModuleService { >(groups, { populate: true }) } - deleteCustomerGroup(groupId: string, sharedContext?: Context): Promise - deleteCustomerGroup( - groupIds: string[], - sharedContext?: Context - ): Promise - deleteCustomerGroup( - selector: CustomerTypes.FilterableCustomerGroupProps, - sharedContext?: Context - ): Promise - - @InjectTransactionManager("baseRepository_") - async deleteCustomerGroup( - groupIdOrSelector: - | string - | string[] - | CustomerTypes.FilterableCustomerGroupProps, - @MedusaContext() sharedContext: Context = {} - ) { - let toDelete = Array.isArray(groupIdOrSelector) - ? groupIdOrSelector - : [groupIdOrSelector as string] - if (isObject(groupIdOrSelector)) { - const ids = await this.customerGroupService_.list( - groupIdOrSelector, - { select: ["id"] }, - sharedContext - ) - toDelete = ids.map(({ id }) => id) - } - - return await this.customerGroupService_.delete(toDelete, sharedContext) - } - async addCustomerToGroup( groupCustomerPair: CustomerTypes.GroupCustomerPair, sharedContext?: Context @@ -425,17 +319,20 @@ export default class CustomerModuleService implements ICustomerModuleService { @MedusaContext() sharedContext: Context = {} ): Promise<{ id: string } | { id: string }[]> { const groupCustomers = await this.customerGroupCustomerService_.create( - Array.isArray(data) ? data : [data], + data, sharedContext ) if (Array.isArray(data)) { - return groupCustomers.map((gc) => ({ id: gc.id })) + return (groupCustomers as unknown as TCustomerGroupCustomer[]).map( + (gc) => ({ id: gc.id }) + ) } - return { id: groupCustomers[0].id } + return { id: groupCustomers.id } } + // TODO: should be createAddresses to conform to the convention async addAddresses( addresses: CustomerTypes.CreateCustomerAddressDTO[], sharedContext?: Context @@ -445,7 +342,7 @@ export default class CustomerModuleService implements ICustomerModuleService { sharedContext?: Context ): Promise - @InjectTransactionManager("baseRepository_") + @InjectManager("baseRepository_") async addAddresses( data: | CustomerTypes.CreateCustomerAddressDTO @@ -454,13 +351,10 @@ export default class CustomerModuleService implements ICustomerModuleService { ): Promise< CustomerTypes.CustomerAddressDTO | CustomerTypes.CustomerAddressDTO[] > { - const addresses = await this.addressService_.create( - Array.isArray(data) ? data : [data], - sharedContext + const addresses = await this.addAddresses_(data, sharedContext).catch( + this.handleDbErrors ) - await this.flush(sharedContext).catch(this.handleDbErrors) - const serialized = await this.baseRepository_.serialize< CustomerTypes.CustomerAddressDTO[] >(addresses, { populate: true }) @@ -472,24 +366,39 @@ export default class CustomerModuleService implements ICustomerModuleService { return serialized[0] } - async updateAddress( + @InjectTransactionManager("baseRepository_") + private async addAddresses_( + data: + | CustomerTypes.CreateCustomerAddressDTO + | CustomerTypes.CreateCustomerAddressDTO[], + @MedusaContext() sharedContext: Context = {} + ) { + const addresses = await this.addressService_.create( + Array.isArray(data) ? data : [data], + sharedContext + ) + + return addresses + } + + async updateAddresses( addressId: string, data: CustomerTypes.UpdateCustomerAddressDTO, sharedContext?: Context ): Promise - async updateAddress( + async updateAddresses( addressIds: string[], data: CustomerTypes.UpdateCustomerAddressDTO, sharedContext?: Context ): Promise - async updateAddress( + async updateAddresses( selector: CustomerTypes.FilterableCustomerAddressProps, data: CustomerTypes.UpdateCustomerAddressDTO, sharedContext?: Context ): Promise @InjectTransactionManager("baseRepository_") - async updateAddress( + async updateAddresses( addressIdOrSelector: | string | string[] @@ -497,7 +406,12 @@ export default class CustomerModuleService implements ICustomerModuleService { data: CustomerTypes.UpdateCustomerAddressDTO, @MedusaContext() sharedContext: Context = {} ) { - let updateData: CustomerTypes.UpdateCustomerAddressDTO[] = [] + let updateData: + | CustomerTypes.UpdateCustomerAddressDTO[] + | { + selector: CustomerTypes.FilterableCustomerAddressProps + data: CustomerTypes.UpdateCustomerAddressDTO + } = [] if (isString(addressIdOrSelector)) { updateData = [ { @@ -511,15 +425,10 @@ export default class CustomerModuleService implements ICustomerModuleService { ...data, })) } else { - const ids = await this.addressService_.list( - addressIdOrSelector, - { select: ["id"] }, - sharedContext - ) - updateData = ids.map(({ id }) => ({ - id, - ...data, - })) + updateData = { + selector: addressIdOrSelector, + data, + } } const addresses = await this.addressService_.update( @@ -540,78 +449,6 @@ export default class CustomerModuleService implements ICustomerModuleService { return serialized } - async deleteAddress(addressId: string, sharedContext?: Context): Promise - async deleteAddress( - addressIds: string[], - sharedContext?: Context - ): Promise - async deleteAddress( - selector: CustomerTypes.FilterableCustomerAddressProps, - sharedContext?: Context - ): Promise - - @InjectTransactionManager("baseRepository_") - async deleteAddress( - addressIdOrSelector: - | string - | string[] - | CustomerTypes.FilterableCustomerAddressProps, - @MedusaContext() sharedContext: Context = {} - ) { - let toDelete = Array.isArray(addressIdOrSelector) - ? addressIdOrSelector - : [addressIdOrSelector as string] - - if (isObject(addressIdOrSelector)) { - const ids = await this.addressService_.list( - addressIdOrSelector, - { select: ["id"] }, - sharedContext - ) - toDelete = ids.map(({ id }) => id) - } - - await this.addressService_.delete(toDelete, sharedContext) - } - - @InjectManager("baseRepository_") - async listAddresses( - filters?: CustomerTypes.FilterableCustomerAddressProps, - config?: FindConfig, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const addresses = await this.addressService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize< - CustomerTypes.CustomerAddressDTO[] - >(addresses, { populate: true }) - } - - @InjectManager("baseRepository_") - async listAndCountAddresses( - filters?: CustomerTypes.FilterableCustomerAddressProps, - config?: FindConfig, - @MedusaContext() sharedContext: Context = {} - ): Promise<[CustomerTypes.CustomerAddressDTO[], number]> { - const [addresses, count] = await this.addressService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - addresses, - { populate: true } - ), - count, - ] - } - async removeCustomerFromGroup( groupCustomerPair: CustomerTypes.GroupCustomerPair, sharedContext?: Context @@ -636,153 +473,6 @@ export default class CustomerModuleService implements ICustomerModuleService { ) } - @InjectManager("baseRepository_") - async listCustomerGroupRelations( - filters?: CustomerTypes.FilterableCustomerGroupCustomerProps, - config?: FindConfig, - @MedusaContext() sharedContext: Context = {} - ) { - const groupCustomers = await this.customerGroupCustomerService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize< - CustomerTypes.CustomerGroupCustomerDTO[] - >(groupCustomers, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async listCustomerGroups( - filters: CustomerTypes.FilterableCustomerGroupProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const groups = await this.customerGroupService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize< - CustomerTypes.CustomerGroupDTO[] - >(groups, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async listAndCountCustomerGroups( - filters: CustomerTypes.FilterableCustomerGroupProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[CustomerTypes.CustomerGroupDTO[], number]> { - const [groups, count] = await this.customerGroupService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - groups, - { - populate: true, - } - ), - count, - ] - } - - @InjectTransactionManager("baseRepository_") - async softDeleteCustomerGroup< - TReturnableLinkableKeys extends string = string - >( - groupIds: string[], - config: SoftDeleteReturn = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const [_, cascadedEntitiesMap] = - await this.customerGroupService_.softDelete(groupIds, sharedContext) - return config.returnLinkableKeys - ? mapObjectTo>( - cascadedEntitiesMap, - entityNameToLinkableKeysMap, - { - pick: config.returnLinkableKeys, - } - ) - : void 0 - } - - @InjectTransactionManager("baseRepository_") - async restoreCustomerGroup( - groupIds: string[], - config: RestoreReturn = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const [_, cascadedEntitiesMap] = await this.customerGroupService_.restore( - groupIds, - sharedContext - ) - return config.returnLinkableKeys - ? mapObjectTo>( - cascadedEntitiesMap, - entityNameToLinkableKeysMap, - { - pick: config.returnLinkableKeys, - } - ) - : void 0 - } - - @InjectTransactionManager("baseRepository_") - async softDelete( - customerIds: string[], - config: SoftDeleteReturn = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const [_, cascadedEntitiesMap] = await this.customerService_.softDelete( - customerIds, - sharedContext - ) - - return config.returnLinkableKeys - ? mapObjectTo>( - cascadedEntitiesMap, - entityNameToLinkableKeysMap, - { - pick: config.returnLinkableKeys, - } - ) - : void 0 - } - - @InjectTransactionManager("baseRepository_") - async restore( - customerIds: string[], - config: RestoreReturn = {}, - @MedusaContext() sharedContext: Context = {} - ) { - const [_, cascadedEntitiesMap] = await this.customerService_.restore( - customerIds, - sharedContext - ) - - return config.returnLinkableKeys - ? mapObjectTo>( - cascadedEntitiesMap, - entityNameToLinkableKeysMap, - { - pick: config.returnLinkableKeys, - } - ) - : void 0 - } - private async flush(context: Context) { const em = (context.manager ?? context.transactionManager) as EntityManager await em.flush() diff --git a/packages/customer/src/services/customer.ts b/packages/customer/src/services/customer.ts deleted file mode 100644 index 3aec4769e4..0000000000 --- a/packages/customer/src/services/customer.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { CustomerTypes, DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { Customer } from "@models" - -type InjectedDependencies = { - customerRepository: DAL.RepositoryService -} - -export default class CustomerService< - TEntity extends Customer = Customer -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CustomerTypes.CreateCustomerDTO - update: CustomerTypes.UpdateCustomerDTO - } ->(Customer) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/customer/src/services/index.ts b/packages/customer/src/services/index.ts index 07e39a5c1c..398679936a 100644 --- a/packages/customer/src/services/index.ts +++ b/packages/customer/src/services/index.ts @@ -1,5 +1 @@ -export { default as AddressService } from "./address" -export { default as CustomerGroupService } from "./customer-group" -export { default as CustomerService } from "./customer" export { default as CustomerModuleService } from "./customer-module" -export { default as CustomerGroupCustomerService } from "./customer-group-customer" diff --git a/packages/customer/src/types/index.ts b/packages/customer/src/types/index.ts index e70f89b103..c993481e0d 100644 --- a/packages/customer/src/types/index.ts +++ b/packages/customer/src/types/index.ts @@ -1,5 +1,8 @@ import { Logger } from "@medusajs/types" -export * from "./address" + +export * as ServiceTypes from "./services" +export * from "./services" + export type InitializeModuleInjectableDependencies = { logger?: Logger } diff --git a/packages/customer/src/types/address.ts b/packages/customer/src/types/services/address.ts similarity index 100% rename from packages/customer/src/types/address.ts rename to packages/customer/src/types/services/address.ts diff --git a/packages/customer/src/types/services/customer-group-customer.ts b/packages/customer/src/types/services/customer-group-customer.ts new file mode 100644 index 0000000000..f51d3b57ab --- /dev/null +++ b/packages/customer/src/types/services/customer-group-customer.ts @@ -0,0 +1,5 @@ +export interface CreateCustomerGroupCustomerDTO { + customer_id: string + customer_group_id: string + created_by?: string +} diff --git a/packages/customer/src/types/services/index.ts b/packages/customer/src/types/services/index.ts new file mode 100644 index 0000000000..c7ac451a5e --- /dev/null +++ b/packages/customer/src/types/services/index.ts @@ -0,0 +1,2 @@ +export * from "./address" +export * from "./customer-group-customer" diff --git a/packages/payment/integration-tests/__tests__/services/payment-module/index.spec.ts b/packages/payment/integration-tests/__tests__/services/payment-module/index.spec.ts index 4aa4ba6926..4f13d0822f 100644 --- a/packages/payment/integration-tests/__tests__/services/payment-module/index.spec.ts +++ b/packages/payment/integration-tests/__tests__/services/payment-module/index.spec.ts @@ -116,7 +116,7 @@ describe("Payment Module Service", () => { expect(collection.length).toEqual(1) - await service.deletePaymentCollection(["pay-col-id-1"]) + await service.deletePaymentCollections(["pay-col-id-1"]) collection = await service.listPaymentCollections({ id: ["pay-col-id-1"], diff --git a/packages/payment/src/services/index.ts b/packages/payment/src/services/index.ts index 01f593ba08..a4f5ea37ae 100644 --- a/packages/payment/src/services/index.ts +++ b/packages/payment/src/services/index.ts @@ -1,2 +1 @@ export { default as PaymentModuleService } from "./payment-module" -export { default as PaymentCollectionService } from "./payment-collection" diff --git a/packages/payment/src/services/payment-collection.ts b/packages/payment/src/services/payment-collection.ts deleted file mode 100644 index abeef3e662..0000000000 --- a/packages/payment/src/services/payment-collection.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { PaymentCollection } from "@models" -import { - CreatePaymentCollectionDTO, - DAL, - UpdatePaymentCollectionDTO, -} from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" - -type InjectedDependencies = { - paymentCollectionRepository: DAL.RepositoryService -} - -export default class PaymentCollectionService< - TEntity extends PaymentCollection = PaymentCollection -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreatePaymentCollectionDTO - update: UpdatePaymentCollectionDTO - } ->(PaymentCollection) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/payment/src/services/payment-module.ts b/packages/payment/src/services/payment-module.ts index 93d4a1310e..1e62e66431 100644 --- a/packages/payment/src/services/payment-module.ts +++ b/packages/payment/src/services/payment-module.ts @@ -4,11 +4,10 @@ import { CreatePaymentDTO, CreatePaymentSessionDTO, DAL, - FilterablePaymentCollectionProps, - FindConfig, InternalModuleDeclaration, IPaymentModuleService, ModuleJoinerConfig, + ModulesSdkTypes, PaymentCollectionDTO, PaymentDTO, SetPaymentSessionsDTO, @@ -16,28 +15,64 @@ import { UpdatePaymentDTO, } from "@medusajs/types" import { - InjectManager, InjectTransactionManager, MedusaContext, + ModulesSdkUtils, } from "@medusajs/utils" -import * as services from "@services" - -import { joinerConfig } from "../joiner-config" +import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" +import { + Capture, + Payment, + PaymentCollection, + PaymentMethodToken, + PaymentProvider, + PaymentSession, + Refund, +} from "@models" type InjectedDependencies = { baseRepository: DAL.RepositoryService - paymentCollectionService: services.PaymentCollectionService + paymentCollectionService: ModulesSdkTypes.InternalModuleService } -export default class PaymentModuleService implements IPaymentModuleService { +const generateMethodForModels = [ + Capture, + PaymentCollection, + PaymentMethodToken, + PaymentProvider, + PaymentSession, + Refund, +] + +export default class PaymentModuleService< + TPaymentCollection extends PaymentCollection = PaymentCollection + > + extends ModulesSdkUtils.abstractModuleServiceFactory< + // TODO revisit when moving forward frane + InjectedDependencies, + PaymentDTO, + { + Capture: { dto: any } + PaymentCollection: { dto: any } + PaymentMethodToken: { dto: any } + PaymentProvider: { dto: any } + PaymentSession: { dto: any } + Refund: { dto: any } + } + >(Payment, generateMethodForModels, entityNameToLinkableKeysMap) + implements IPaymentModuleService +{ protected baseRepository_: DAL.RepositoryService - protected paymentCollectionService_: services.PaymentCollectionService + protected paymentCollectionService_: ModulesSdkTypes.InternalModuleService constructor( { baseRepository, paymentCollectionService }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { + // @ts-ignore + super(...arguments) + this.baseRepository_ = baseRepository this.paymentCollectionService_ = paymentCollectionService @@ -105,85 +140,6 @@ export default class PaymentModuleService implements IPaymentModuleService { ) } - deletePaymentCollection( - paymentCollectionId: string[], - sharedContext?: Context - ): Promise - deletePaymentCollection( - paymentCollectionId: string, - sharedContext?: Context - ): Promise - - @InjectTransactionManager("baseRepository_") - async deletePaymentCollection( - ids: string | string[], - @MedusaContext() sharedContext?: Context - ): Promise { - const paymentCollectionIds = Array.isArray(ids) ? ids : [ids] - await this.paymentCollectionService_.delete( - paymentCollectionIds, - sharedContext - ) - } - - @InjectManager("baseRepository_") - async retrievePaymentCollection( - paymentCollectionId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const paymentCollection = await this.paymentCollectionService_.retrieve( - paymentCollectionId, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - paymentCollection, - { populate: true } - ) - } - - @InjectManager("baseRepository_") - async listPaymentCollections( - filters: FilterablePaymentCollectionProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext?: Context - ): Promise { - const paymentCollections = await this.paymentCollectionService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - paymentCollections, - { populate: true } - ) - } - - @InjectManager("baseRepository_") - async listAndCountPaymentCollections( - filters: FilterablePaymentCollectionProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext?: Context - ): Promise<[PaymentCollectionDTO[], number]> { - const [paymentCollections, count] = - await this.paymentCollectionService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - paymentCollections, - { populate: true } - ), - count, - ] - } - /** * TODO */ diff --git a/packages/payment/src/types/repositories.ts b/packages/payment/src/types/repositories.ts deleted file mode 100644 index cc84166e9a..0000000000 --- a/packages/payment/src/types/repositories.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { - DAL, - CreatePaymentCollectionDTO, - UpdatePaymentCollectionDTO, -} from "@medusajs/types" - -import { PaymentCollection } from "@models" - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPaymentCollectionRepository< - TEntity extends PaymentCollection = PaymentCollection -> extends DAL.RepositoryService< - TEntity, - { - create: CreatePaymentCollectionDTO - update: UpdatePaymentCollectionDTO - } - > {} diff --git a/packages/pricing/integration-tests/__tests__/services/currency/index.spec.ts b/packages/pricing/integration-tests/__tests__/services/currency/index.spec.ts index 33400946d4..cf054ed3ae 100644 --- a/packages/pricing/integration-tests/__tests__/services/currency/index.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/currency/index.spec.ts @@ -183,7 +183,7 @@ describe("Currency Service", () => { error = e } - expect(error.message).toEqual('"currencyCode" must be defined') + expect(error.message).toEqual("currency - code must be defined") }) it("should return currency based on config select param", async () => { diff --git a/packages/pricing/integration-tests/__tests__/services/money-amount/index.spec.ts b/packages/pricing/integration-tests/__tests__/services/money-amount/index.spec.ts index ae6a8cf2b6..618857e6db 100644 --- a/packages/pricing/integration-tests/__tests__/services/money-amount/index.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/money-amount/index.spec.ts @@ -258,7 +258,7 @@ describe("MoneyAmount Service", () => { error = e } - expect(error.message).toEqual('"moneyAmountId" must be defined') + expect(error.message).toEqual("moneyAmount - id must be defined") }) it("should return moneyAmount based on config select param", async () => { diff --git a/packages/pricing/integration-tests/__tests__/services/price-list-rule/index.spec.ts b/packages/pricing/integration-tests/__tests__/services/price-list-rule/index.spec.ts index f677a10fc0..3e953563ea 100644 --- a/packages/pricing/integration-tests/__tests__/services/price-list-rule/index.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/price-list-rule/index.spec.ts @@ -162,7 +162,7 @@ describe("PriceListRule Service", () => { error = e } - expect(error.message).toEqual('"priceListRuleId" must be defined') + expect(error.message).toEqual("priceListRule - id must be defined") }) }) diff --git a/packages/pricing/integration-tests/__tests__/services/price-list/index.spec.ts b/packages/pricing/integration-tests/__tests__/services/price-list/index.spec.ts index 79c2985044..026bc3186b 100644 --- a/packages/pricing/integration-tests/__tests__/services/price-list/index.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/price-list/index.spec.ts @@ -157,7 +157,7 @@ describe("PriceList Service", () => { error = e } - expect(error.message).toEqual('"priceListId" must be defined') + expect(error.message).toEqual("priceList - id must be defined") }) }) diff --git a/packages/pricing/integration-tests/__tests__/services/price-rule/index.spec.ts b/packages/pricing/integration-tests/__tests__/services/price-rule/index.spec.ts index 81c0eb3dff..e8402dba64 100644 --- a/packages/pricing/integration-tests/__tests__/services/price-rule/index.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/price-rule/index.spec.ts @@ -219,7 +219,7 @@ describe("PriceRule Service", () => { error = e } - expect(error.message).toEqual('"priceRuleId" must be defined') + expect(error.message).toEqual("priceRule - id must be defined") }) it("should return priceRule based on config select param", async () => { diff --git a/packages/pricing/integration-tests/__tests__/services/price-set-money-amonut-rules/index.spec.ts b/packages/pricing/integration-tests/__tests__/services/price-set-money-amonut-rules/index.spec.ts index 4c80f1a47c..8f5848a1d0 100644 --- a/packages/pricing/integration-tests/__tests__/services/price-set-money-amonut-rules/index.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/price-set-money-amonut-rules/index.spec.ts @@ -168,7 +168,7 @@ describe("PriceSetMoneyAmountRules Service", () => { } expect(error.message).toEqual( - '"priceSetMoneyAmountRulesId" must be defined' + "priceSetMoneyAmountRules - id must be defined" ) }) diff --git a/packages/pricing/integration-tests/__tests__/services/price-set/index.spec.ts b/packages/pricing/integration-tests/__tests__/services/price-set/index.spec.ts index 70ef27e8b4..161bced693 100644 --- a/packages/pricing/integration-tests/__tests__/services/price-set/index.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/price-set/index.spec.ts @@ -305,7 +305,7 @@ describe("PriceSet Service", () => { error = e } - expect(error.message).toEqual('"priceSetId" must be defined') + expect(error.message).toEqual("priceSet - id must be defined") }) it("should return priceSet based on config select param", async () => { diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/currency.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/currency.spec.ts index 3c76e717b8..ae2865a504 100644 --- a/packages/pricing/integration-tests/__tests__/services/pricing-module/currency.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/currency.spec.ts @@ -180,7 +180,7 @@ describe("PricingModule Service - Currency", () => { error = e } - expect(error.message).toEqual('"currencyCode" must be defined') + expect(error.message).toEqual("currency - code must be defined") }) it("should return currency based on config select param", async () => { diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/money-amount.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/money-amount.spec.ts index 76adb62a22..c1e47a73a9 100644 --- a/packages/pricing/integration-tests/__tests__/services/pricing-module/money-amount.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/money-amount.spec.ts @@ -245,7 +245,7 @@ describe("PricingModule Service - MoneyAmount", () => { error = e } - expect(error.message).toEqual('"moneyAmountId" must be defined') + expect(error.message).toEqual("moneyAmount - id must be defined") }) it("should return moneyAmount based on config select param", async () => { @@ -320,7 +320,7 @@ describe("PricingModule Service - MoneyAmount", () => { }) }) - describe("restoreDeletedMoneyAmounts", () => { + describe("restoreMoneyAmounts", () => { const id = "money-amount-USD" it("should restore softDeleted priceSetMoneyAmount and PriceRule when restoring soft-deleting money amount", async () => { @@ -330,7 +330,7 @@ describe("PricingModule Service - MoneyAmount", () => { await createPriceRules(testManager) await createPriceSetMoneyAmountRules(testManager) await service.softDeleteMoneyAmounts([id]) - await service.restoreDeletedMoneyAmounts([id]) + await service.restoreMoneyAmounts([id]) const [moneyAmount] = await service.listMoneyAmounts( { diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-list-rule.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-list-rule.spec.ts index f659615812..713f8fb696 100644 --- a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-list-rule.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-list-rule.spec.ts @@ -171,7 +171,7 @@ describe("PriceListRule Service", () => { error = e } - expect(error.message).toEqual('"priceListRuleId" must be defined') + expect(error.message).toEqual("priceListRule - id must be defined") }) }) @@ -283,7 +283,7 @@ describe("PriceListRule Service", () => { expect(priceList.price_list_rules).toEqual( expect.arrayContaining([ expect.objectContaining({ - rule_type: "rule-type-3", + rule_type: { id: "rule-type-3" }, price_list_rule_values: [ expect.objectContaining({ value: "sc-1" }), ], @@ -323,7 +323,7 @@ describe("PriceListRule Service", () => { expect(priceList.price_list_rules).toEqual( expect.arrayContaining([ expect.objectContaining({ - rule_type: "rule-type-3", + rule_type: { id: "rule-type-3" }, price_list_rule_values: expect.arrayContaining([ expect.objectContaining({ value: "sc-1" }), expect.objectContaining({ value: "sc-2" }), @@ -351,7 +351,7 @@ describe("PriceListRule Service", () => { ) expect(priceList.price_list_rules).toEqual([ - expect.objectContaining({ rule_type: "rule-type-2" }), + expect.objectContaining({ rule_type: { id: "rule-type-2" } }), ]) }) }) diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-list.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-list.spec.ts index 774ceec504..eb41c50b9f 100644 --- a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-list.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-list.spec.ts @@ -179,7 +179,7 @@ describe("PriceList Service", () => { error = e } - expect(error.message).toEqual('"priceListId" must be defined') + expect(error.message).toEqual("priceList - id must be defined") }) }) diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-rule.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-rule.spec.ts index d447055216..7f3a619ec8 100644 --- a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-rule.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-rule.spec.ts @@ -224,7 +224,7 @@ describe("PricingModule Service - PriceRule", () => { error = e } - expect(error.message).toEqual('"priceRuleId" must be defined') + expect(error.message).toEqual("priceRule - id must be defined") }) it("should return PriceRule based on config select param", async () => { diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-set-money-amount-rules.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-set-money-amount-rules.spec.ts index 076a0d2c3f..db74001808 100644 --- a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-set-money-amount-rules.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-set-money-amount-rules.spec.ts @@ -192,7 +192,7 @@ describe("PricingModule Service - PriceSetMoneyAmountRules", () => { } expect(error.message).toEqual( - '"priceSetMoneyAmountRulesId" must be defined' + "priceSetMoneyAmountRules - id must be defined" ) }) diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-set.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-set.spec.ts index 41ffa5c4dd..ac6ee27716 100644 --- a/packages/pricing/integration-tests/__tests__/services/pricing-module/price-set.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/price-set.spec.ts @@ -248,7 +248,7 @@ describe("PricingModule Service - PriceSet", () => { error = e } - expect(error.message).toEqual('"priceSetId" must be defined') + expect(error.message).toEqual("priceSet - id must be defined") }) it("should return priceSet based on config select param", async () => { diff --git a/packages/pricing/integration-tests/__tests__/services/pricing-module/rule-type.spec.ts b/packages/pricing/integration-tests/__tests__/services/pricing-module/rule-type.spec.ts index 2011087b97..2c04056122 100644 --- a/packages/pricing/integration-tests/__tests__/services/pricing-module/rule-type.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/pricing-module/rule-type.spec.ts @@ -170,7 +170,7 @@ describe("PricingModuleService ruleType", () => { error = e } - expect(error.message).toEqual('"ruleTypeId" must be defined') + expect(error.message).toEqual("ruleType - id must be defined") }) it("should return ruleType based on config select param", async () => { diff --git a/packages/pricing/integration-tests/__tests__/services/rule-type/index.spec.ts b/packages/pricing/integration-tests/__tests__/services/rule-type/index.spec.ts index a2f038ee96..df7431aa38 100644 --- a/packages/pricing/integration-tests/__tests__/services/rule-type/index.spec.ts +++ b/packages/pricing/integration-tests/__tests__/services/rule-type/index.spec.ts @@ -164,7 +164,7 @@ describe("RuleType Service", () => { error = e } - expect(error.message).toEqual('"ruleTypeId" must be defined') + expect(error.message).toEqual("ruleType - id must be defined") }) it("should return ruleType based on config select param", async () => { diff --git a/packages/pricing/src/services/__fixtures__/currency.ts b/packages/pricing/src/services/__fixtures__/currency.ts index 27315b54df..6ecdd89022 100644 --- a/packages/pricing/src/services/__fixtures__/currency.ts +++ b/packages/pricing/src/services/__fixtures__/currency.ts @@ -1,6 +1,5 @@ import { Currency } from "@models" -import { CurrencyService } from "@services" -import { asClass, asValue, createContainer } from "awilix" +import { asValue } from "awilix" ;(Currency as any).meta = { /** @@ -10,10 +9,7 @@ import { asClass, asValue, createContainer } from "awilix" } export const nonExistingCurrencyCode = "non-existing-code" -export const mockContainer = createContainer() - -mockContainer.register({ - transaction: asValue(async (task) => await task()), +export const currencyRepositoryMock = { currencyRepository: asValue({ find: jest.fn().mockImplementation(async ({ where: { code } }) => { if (code === nonExistingCurrencyCode) { @@ -25,5 +21,4 @@ mockContainer.register({ findAndCount: jest.fn().mockResolvedValue([[], 0]), getFreshManager: jest.fn().mockResolvedValue({}), }), - currencyService: asClass(CurrencyService), -}) +} diff --git a/packages/pricing/src/services/__tests__/currency.spec.ts b/packages/pricing/src/services/__tests__/currency.spec.ts index 2c130ec5ba..46cc0f789c 100644 --- a/packages/pricing/src/services/__tests__/currency.spec.ts +++ b/packages/pricing/src/services/__tests__/currency.spec.ts @@ -1,18 +1,31 @@ import { - mockContainer, + currencyRepositoryMock, nonExistingCurrencyCode, } from "../__fixtures__/currency" +import { createMedusaContainer } from "@medusajs/utils" +import { asValue } from "awilix" +import ContainerLoader from "../../loaders/container" +import { MedusaContainer } from "@medusajs/types" const code = "existing-currency" describe("Currency service", function () { - beforeEach(function () { + let container: MedusaContainer + + beforeEach(async function () { jest.clearAllMocks() + + container = createMedusaContainer() + container.register("manager", asValue({})) + + await ContainerLoader({ container }) + + container.register(currencyRepositoryMock) }) it("should retrieve a currency", async function () { - const currencyService = mockContainer.resolve("currencyService") - const currencyRepository = mockContainer.resolve("currencyRepository") + const currencyService = container.resolve("currencyService") + const currencyRepository = container.resolve("currencyRepository") await currencyService.retrieve(code) @@ -33,8 +46,8 @@ describe("Currency service", function () { }) it("should fail to retrieve a currency", async function () { - const currencyService = mockContainer.resolve("currencyService") - const currencyRepository = mockContainer.resolve("currencyRepository") + const currencyService = container.resolve("currencyService") + const currencyRepository = container.resolve("currencyRepository") const err = await currencyService .retrieve(nonExistingCurrencyCode) @@ -62,8 +75,8 @@ describe("Currency service", function () { }) it("should list currencys", async function () { - const currencyService = mockContainer.resolve("currencyService") - const currencyRepository = mockContainer.resolve("currencyRepository") + const currencyService = container.resolve("currencyService") + const currencyRepository = container.resolve("currencyRepository") const filters = {} const config = { @@ -88,8 +101,8 @@ describe("Currency service", function () { }) it("should list currencys with filters", async function () { - const currencyService = mockContainer.resolve("currencyService") - const currencyRepository = mockContainer.resolve("currencyRepository") + const currencyService = container.resolve("currencyService") + const currencyRepository = container.resolve("currencyRepository") const filters = { tags: { @@ -126,8 +139,8 @@ describe("Currency service", function () { }) it("should list currencys with filters and relations", async function () { - const currencyService = mockContainer.resolve("currencyService") - const currencyRepository = mockContainer.resolve("currencyRepository") + const currencyService = container.resolve("currencyService") + const currencyRepository = container.resolve("currencyRepository") const filters = { tags: { @@ -163,9 +176,9 @@ describe("Currency service", function () { ) }) - it("should list and count the currencys with filters and relations", async function () { - const currencyService = mockContainer.resolve("currencyService") - const currencyRepository = mockContainer.resolve("currencyRepository") + it("should list and count the currencies with filters and relations", async function () { + const currencyService = container.resolve("currencyService") + const currencyRepository = container.resolve("currencyRepository") const filters = { tags: { diff --git a/packages/pricing/src/services/currency.ts b/packages/pricing/src/services/currency.ts deleted file mode 100644 index d7df5abda4..0000000000 --- a/packages/pricing/src/services/currency.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { Currency } from "@models" -import { ServiceTypes } from "@types" - -type InjectedDependencies = { - currencyRepository: DAL.RepositoryService -} - -export default class CurrencyService< - TEntity extends Currency = Currency -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ServiceTypes.CreateCurrencyDTO - update: ServiceTypes.UpdateCurrencyDTO - } ->(Currency) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/pricing/src/services/index.ts b/packages/pricing/src/services/index.ts index 7e67ff0a55..5d08291b40 100644 --- a/packages/pricing/src/services/index.ts +++ b/packages/pricing/src/services/index.ts @@ -1,12 +1,6 @@ -export { default as CurrencyService } from "./currency" -export { default as MoneyAmountService } from "./money-amount" export { default as PriceListService } from "./price-list" export { default as PriceListRuleService } from "./price-list-rule" export { default as PriceListRuleValueService } from "./price-list-rule-value" export { default as PriceRuleService } from "./price-rule" -export { default as PriceSetService } from "./price-set" -export { default as PriceSetMoneyAmountService } from "./price-set-money-amount" -export { default as PriceSetMoneyAmountRulesService } from "./price-set-money-amount-rules" -export { default as PriceSetRuleTypeService } from "./price-set-rule-type" export { default as PricingModuleService } from "./pricing-module" export { default as RuleTypeService } from "./rule-type" diff --git a/packages/pricing/src/services/money-amount.ts b/packages/pricing/src/services/money-amount.ts deleted file mode 100644 index b73422969e..0000000000 --- a/packages/pricing/src/services/money-amount.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { MoneyAmount } from "@models" -import { ServiceTypes } from "@types" - -type InjectedDependencies = { - moneyAmountRepository: DAL.RepositoryService -} - -export default class MoneyAmountService< - TEntity extends MoneyAmount = MoneyAmount -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ServiceTypes.CreateMoneyAmountDTO - update: ServiceTypes.UpdateMoneyAmountDTO - }, - { - list: ServiceTypes.FilterableMoneyAmountProps - listAndCount: ServiceTypes.FilterableMoneyAmountProps - } ->(MoneyAmount) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/pricing/src/services/price-list-rule-value.ts b/packages/pricing/src/services/price-list-rule-value.ts index 10b5cc9ed3..88d4f02414 100644 --- a/packages/pricing/src/services/price-list-rule-value.ts +++ b/packages/pricing/src/services/price-list-rule-value.ts @@ -9,26 +9,32 @@ type InjectedDependencies = { export default class PriceListRuleValueService< TEntity extends PriceListRuleValue = PriceListRuleValue -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - update: ServiceTypes.UpdatePriceListRuleValueDTO - }, - { - list: ServiceTypes.FilterablePriceListRuleValueProps - listAndCount: ServiceTypes.FilterablePriceListRuleValueProps - } ->(PriceListRuleValue) { +> extends ModulesSdkUtils.internalModuleServiceFactory( + PriceListRuleValue +) { constructor(container: InjectedDependencies) { // @ts-ignore super(...arguments) } - async create( + create( data: ServiceTypes.CreatePriceListRuleValueDTO[], + context: Context + ): Promise + + create( + data: ServiceTypes.CreatePriceListRuleValueDTO, + context: Context + ): Promise + + async create( + data: + | ServiceTypes.CreatePriceListRuleValueDTO + | ServiceTypes.CreatePriceListRuleValueDTO[], context: Context = {} - ): Promise { - const priceListRuleValues = data.map((priceRuleValueData) => { + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + const priceListRuleValues = data_.map((priceRuleValueData) => { const { price_list_rule_id: priceListRuleId, ...priceRuleValue } = priceRuleValueData diff --git a/packages/pricing/src/services/price-list-rule.ts b/packages/pricing/src/services/price-list-rule.ts index cb9ddb7487..438b712b2f 100644 --- a/packages/pricing/src/services/price-list-rule.ts +++ b/packages/pricing/src/services/price-list-rule.ts @@ -9,27 +9,31 @@ type InjectedDependencies = { export default class PriceListRuleService< TEntity extends PriceListRule = PriceListRule -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ServiceTypes.CreatePriceListRuleDTO - update: ServiceTypes.UpdatePriceListRuleDTO - }, - { - list: ServiceTypes.FilterablePriceListRuleProps - listAndCount: ServiceTypes.FilterablePriceListRuleProps - } ->(PriceListRule) { +> extends ModulesSdkUtils.internalModuleServiceFactory( + PriceListRule +) { constructor(container: InjectedDependencies) { // @ts-ignore super(...arguments) } - async create( + create( data: ServiceTypes.CreatePriceListRuleDTO[], + sharedContext?: Context + ): Promise + create( + data: ServiceTypes.CreatePriceListRuleDTO, + sharedContext?: Context + ): Promise + + async create( + data: + | ServiceTypes.CreatePriceListRuleDTO + | ServiceTypes.CreatePriceListRuleDTO[], context: Context = {} - ): Promise { - const priceListRule = data.map((priceListRule) => { + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + const priceListRule = data_.map((priceListRule) => { const { price_list_id: priceListId, rule_type_id: ruleTypeId, @@ -50,11 +54,28 @@ export default class PriceListRuleService< return await super.create(priceListRule, context) } - async update( + // @ts-ignore + update( data: ServiceTypes.UpdatePriceListRuleDTO[], + context: Context + ): Promise + + // @ts-ignore + update( + data: ServiceTypes.UpdatePriceListRuleDTO, + context: Context + ): Promise + + // TODO add support for selector? and then rm ts ignore + // @ts-ignore + async update( + data: + | ServiceTypes.UpdatePriceListRuleDTO + | ServiceTypes.UpdatePriceListRuleDTO[], context: Context = {} - ): Promise { - const priceListRules = data.map((priceListRule) => { + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + const priceListRules = data_.map((priceListRule) => { const { price_list_id, rule_type_id, ...priceListRuleData } = priceListRule diff --git a/packages/pricing/src/services/price-list.ts b/packages/pricing/src/services/price-list.ts index c5ddc99398..9810a6a8da 100644 --- a/packages/pricing/src/services/price-list.ts +++ b/packages/pricing/src/services/price-list.ts @@ -9,32 +9,45 @@ type InjectedDependencies = { export default class PriceListService< TEntity extends PriceList = PriceList -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - {}, - { - list: ServiceTypes.FilterablePriceListProps - listAndCount: ServiceTypes.FilterablePriceListProps - } ->(PriceList) { +> extends ModulesSdkUtils.internalModuleServiceFactory( + PriceList +) { constructor(container: InjectedDependencies) { // @ts-ignore super(...arguments) } - async create( + create( data: ServiceTypes.CreatePriceListDTO[], sharedContext?: Context - ): Promise { - const priceLists = this.normalizePriceListDate(data) + ): Promise + create( + data: ServiceTypes.CreatePriceListDTO, + sharedContext?: Context + ): Promise + + async create( + data: ServiceTypes.CreatePriceListDTO | ServiceTypes.CreatePriceListDTO[], + sharedContext?: Context + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + const priceLists = this.normalizePriceListDate(data_) return await super.create(priceLists, sharedContext) } + // @ts-ignore + update(data: any[], sharedContext?: Context): Promise + // @ts-ignore + update(data: any, sharedContext?: Context): Promise + + // TODO: Add support for selector? and then rm ts ignore + // @ts-ignore async update( - data: ServiceTypes.UpdatePriceListDTO[], + data: ServiceTypes.UpdatePriceListDTO | ServiceTypes.UpdatePriceListDTO[], sharedContext?: Context - ): Promise { - const priceLists = this.normalizePriceListDate(data) + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + const priceLists = this.normalizePriceListDate(data_) return await super.update(priceLists, sharedContext) } diff --git a/packages/pricing/src/services/price-rule.ts b/packages/pricing/src/services/price-rule.ts index 1c3f365e5c..a0d8ce13ca 100644 --- a/packages/pricing/src/services/price-rule.ts +++ b/packages/pricing/src/services/price-rule.ts @@ -10,26 +10,29 @@ type InjectedDependencies = { export default class PriceRuleService< TEntity extends PriceRule = PriceRule -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - update: ServiceTypes.UpdatePriceRuleDTO - }, - { - list: ServiceTypes.FilterablePriceRuleProps - listAndCount: ServiceTypes.FilterablePriceRuleProps - } ->(PriceRule) { +> extends ModulesSdkUtils.internalModuleServiceFactory( + PriceRule +) { constructor(container: InjectedDependencies) { // @ts-ignore super(...arguments) } - async create( + create( data: ServiceTypes.CreatePriceRuleDTO[], sharedContext?: Context - ): Promise { - const toCreate = data.map((ruleData) => { + ): Promise + create( + data: ServiceTypes.CreatePriceRuleDTO, + sharedContext?: Context + ): Promise + + async create( + data: ServiceTypes.CreatePriceRuleDTO | ServiceTypes.CreatePriceRuleDTO[], + sharedContext: Context = {} + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + const toCreate = data_.map((ruleData) => { const ruleDataClone = { ...ruleData } as any ruleDataClone.rule_type ??= ruleData.rule_type_id diff --git a/packages/pricing/src/services/price-set-money-amount-rules.ts b/packages/pricing/src/services/price-set-money-amount-rules.ts deleted file mode 100644 index a1915770cf..0000000000 --- a/packages/pricing/src/services/price-set-money-amount-rules.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { PriceSetMoneyAmountRules } from "@models" -import { ServiceTypes } from "@types" - -type InjectedDependencies = { - priceSetMoneyAmountRulesRepository: DAL.RepositoryService -} - -export default class PriceSetMoneyAmountRulesService< - TEntity extends PriceSetMoneyAmountRules = PriceSetMoneyAmountRules -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ServiceTypes.CreatePriceSetMoneyAmountRulesDTO - update: ServiceTypes.UpdatePriceSetMoneyAmountRulesDTO - }, - { - list: ServiceTypes.FilterablePriceSetMoneyAmountRulesProps - listAndCount: ServiceTypes.FilterablePriceSetMoneyAmountRulesProps - } ->(PriceSetMoneyAmountRules) { - constructor({ priceSetMoneyAmountRulesRepository }: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/pricing/src/services/price-set-money-amount.ts b/packages/pricing/src/services/price-set-money-amount.ts deleted file mode 100644 index 78644213d6..0000000000 --- a/packages/pricing/src/services/price-set-money-amount.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { PriceSetMoneyAmount } from "@models" -import { ServiceTypes } from "@types" - -type InjectedDependencies = { - priceSetMoneyAmountRepository: DAL.RepositoryService -} - -export default class PriceSetMoneyAmountService< - TEntity extends PriceSetMoneyAmount = PriceSetMoneyAmount -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ServiceTypes.CreatePriceSetMoneyAmountDTO - update: ServiceTypes.UpdatePriceSetMoneyAmountDTO - }, - { - list: ServiceTypes.FilterablePriceSetMoneyAmountProps - listAndCount: ServiceTypes.FilterablePriceSetMoneyAmountProps - } ->(PriceSetMoneyAmount) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/pricing/src/services/price-set-rule-type.ts b/packages/pricing/src/services/price-set-rule-type.ts deleted file mode 100644 index 452050ebd6..0000000000 --- a/packages/pricing/src/services/price-set-rule-type.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { PriceSetRuleType } from "@models" -import { ServiceTypes } from "@types" - -type InjectedDependencies = { - priceSetRuleTypeRepository: DAL.RepositoryService -} - -export default class PriceSetRuleTypeService< - TEntity extends PriceSetRuleType = PriceSetRuleType -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ServiceTypes.CreatePriceSetRuleTypeDTO - update: ServiceTypes.UpdatePriceSetRuleTypeDTO - }, - { - list: ServiceTypes.FilterablePriceSetRuleTypeProps - listAndCount: ServiceTypes.FilterablePriceSetRuleTypeProps - } ->(PriceSetRuleType) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/pricing/src/services/price-set.ts b/packages/pricing/src/services/price-set.ts deleted file mode 100644 index c850f045d7..0000000000 --- a/packages/pricing/src/services/price-set.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { PriceSet } from "@models" - -import { ServiceTypes } from "@types" - -type InjectedDependencies = { - priceSetRepository: DAL.RepositoryService -} - -export default class PriceSetService< - TEntity extends PriceSet = PriceSet -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: Omit - update: Omit - }, - { - list: ServiceTypes.FilterablePriceSetProps - listAndCount: ServiceTypes.FilterablePriceSetProps - } ->(PriceSet) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/pricing/src/services/pricing-module.ts b/packages/pricing/src/services/pricing-module.ts index c96c6e639e..b588915df3 100644 --- a/packages/pricing/src/services/pricing-module.ts +++ b/packages/pricing/src/services/pricing-module.ts @@ -4,27 +4,26 @@ import { CreateMoneyAmountDTO, CreatePriceListRuleDTO, DAL, - FindConfig, InternalModuleDeclaration, ModuleJoinerConfig, + ModulesSdkTypes, PriceSetDTO, PricingContext, PricingFilters, PricingRepositoryService, PricingTypes, - RestoreReturn, RuleTypeDTO, } from "@medusajs/types" import { + arrayDifference, + deduplicate, + groupBy, InjectManager, InjectTransactionManager, MedusaContext, MedusaError, + ModulesSdkUtils, PriceListType, - arrayDifference, - deduplicate, - groupBy, - mapObjectTo, removeNullish, } from "@medusajs/utils" @@ -43,66 +42,86 @@ import { } from "@models" import { - CurrencyService, - MoneyAmountService, PriceListRuleService, PriceListRuleValueService, PriceListService, PriceRuleService, - PriceSetMoneyAmountRulesService, - PriceSetMoneyAmountService, - PriceSetRuleTypeService, - PriceSetService, RuleTypeService, } from "@services" -import { ServiceTypes } from "@types" -import { validatePriceListDates } from "@utils" -import { CreatePriceListRuleValueDTO } from "src/types/services" -import { - LinkableKeys, - entityNameToLinkableKeysMap, - joinerConfig, -} from "../joiner-config" +import {entityNameToLinkableKeysMap, joinerConfig} from "../joiner-config" +import {validatePriceListDates} from "@utils" +import {ServiceTypes} from "@types" + type InjectedDependencies = { baseRepository: DAL.RepositoryService pricingRepository: PricingRepositoryService - currencyService: CurrencyService - moneyAmountService: MoneyAmountService - priceSetService: PriceSetService - priceSetMoneyAmountRulesService: PriceSetMoneyAmountRulesService + currencyService: ModulesSdkTypes.InternalModuleService + moneyAmountService: ModulesSdkTypes.InternalModuleService + priceSetService: ModulesSdkTypes.InternalModuleService + priceSetMoneyAmountRulesService: ModulesSdkTypes.InternalModuleService ruleTypeService: RuleTypeService priceRuleService: PriceRuleService - priceSetRuleTypeService: PriceSetRuleTypeService - priceSetMoneyAmountService: PriceSetMoneyAmountService + priceSetRuleTypeService: ModulesSdkTypes.InternalModuleService + priceSetMoneyAmountService: ModulesSdkTypes.InternalModuleService priceListService: PriceListService priceListRuleService: PriceListRuleService priceListRuleValueService: PriceListRuleValueService } +const generateMethodForModels = [ + Currency, + MoneyAmount, + PriceList, + PriceListRule, + PriceListRuleValue, + PriceRule, + PriceSetMoneyAmount, + PriceSetMoneyAmountRules, + PriceSetRuleType, + RuleType, +] + export default class PricingModuleService< - TPriceSet extends PriceSet = PriceSet, - TMoneyAmount extends MoneyAmount = MoneyAmount, - TCurrency extends Currency = Currency, - TRuleType extends RuleType = RuleType, - TPriceSetMoneyAmountRules extends PriceSetMoneyAmountRules = PriceSetMoneyAmountRules, - TPriceRule extends PriceRule = PriceRule, - TPriceSetRuleType extends PriceSetRuleType = PriceSetRuleType, - TPriceSetMoneyAmount extends PriceSetMoneyAmount = PriceSetMoneyAmount, - TPriceList extends PriceList = PriceList, - TPriceListRule extends PriceListRule = PriceListRule, - TPriceListRuleValue extends PriceListRuleValue = PriceListRuleValue -> implements PricingTypes.IPricingModuleService + TPriceSet extends PriceSet = PriceSet, + TMoneyAmount extends MoneyAmount = MoneyAmount, + TCurrency extends Currency = Currency, + TRuleType extends RuleType = RuleType, + TPriceSetMoneyAmountRules extends PriceSetMoneyAmountRules = PriceSetMoneyAmountRules, + TPriceRule extends PriceRule = PriceRule, + TPriceSetRuleType extends PriceSetRuleType = PriceSetRuleType, + TPriceSetMoneyAmount extends PriceSetMoneyAmount = PriceSetMoneyAmount, + TPriceList extends PriceList = PriceList, + TPriceListRule extends PriceListRule = PriceListRule, + TPriceListRuleValue extends PriceListRuleValue = PriceListRuleValue + > + extends ModulesSdkUtils.abstractModuleServiceFactory< + InjectedDependencies, + PricingTypes.PriceSetDTO, + { + Currency: { dto: PricingTypes.CurrencyDTO } + MoneyAmount: { dto: PricingTypes.MoneyAmountDTO } + PriceSetMoneyAmount: { dto: PricingTypes.PriceSetMoneyAmountDTO } + PriceSetMoneyAmountRules: { + dto: PricingTypes.PriceSetMoneyAmountRulesDTO + } + PriceRule: { dto: PricingTypes.PriceRuleDTO } + RuleType: { dto: PricingTypes.RuleTypeDTO } + PriceList: { dto: PricingTypes.PriceListDTO } + PriceListRule: { dto: PricingTypes.PriceListRuleDTO } + } + >(PriceSet, generateMethodForModels, entityNameToLinkableKeysMap) + implements PricingTypes.IPricingModuleService { protected baseRepository_: DAL.RepositoryService protected readonly pricingRepository_: PricingRepositoryService - protected readonly currencyService_: CurrencyService - protected readonly moneyAmountService_: MoneyAmountService + protected readonly currencyService_: ModulesSdkTypes.InternalModuleService + protected readonly moneyAmountService_: ModulesSdkTypes.InternalModuleService protected readonly ruleTypeService_: RuleTypeService - protected readonly priceSetService_: PriceSetService - protected readonly priceSetMoneyAmountRulesService_: PriceSetMoneyAmountRulesService + protected readonly priceSetService_: ModulesSdkTypes.InternalModuleService + protected readonly priceSetMoneyAmountRulesService_: ModulesSdkTypes.InternalModuleService protected readonly priceRuleService_: PriceRuleService - protected readonly priceSetRuleTypeService_: PriceSetRuleTypeService - protected readonly priceSetMoneyAmountService_: PriceSetMoneyAmountService + protected readonly priceSetRuleTypeService_: ModulesSdkTypes.InternalModuleService + protected readonly priceSetMoneyAmountService_: ModulesSdkTypes.InternalModuleService protected readonly priceListService_: PriceListService protected readonly priceListRuleService_: PriceListRuleService protected readonly priceListRuleValueService_: PriceListRuleValueService @@ -125,6 +144,9 @@ export default class PricingModuleService< }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { + // @ts-ignore + super(...arguments) + this.baseRepository_ = baseRepository this.pricingRepository_ = pricingRepository this.currencyService_ = currencyService @@ -215,66 +237,6 @@ export default class PricingModuleService< return JSON.parse(JSON.stringify(calculatedPrices)) } - @InjectManager("baseRepository_") - async retrieve( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const priceSet = await this.priceSetService_.retrieve( - id, - config, - sharedContext - ) - - return this.baseRepository_.serialize(priceSet, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async list( - filters: PricingTypes.FilterablePriceSetProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const priceSets = await this.priceSetService_.list( - filters, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - priceSets, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCount( - filters: PricingTypes.FilterablePriceSetProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PricingTypes.PriceSetDTO[], number]> { - const [priceSets, count] = await this.priceSetService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - priceSets, - { - populate: true, - } - ), - count, - ] - } - async create( data: PricingTypes.CreatePriceSetDTO, sharedContext?: Context @@ -743,7 +705,7 @@ export default class PricingModuleService< ) { const priceSets = await this.priceSetService_.update(data, sharedContext) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( priceSets, { populate: true, @@ -751,77 +713,6 @@ export default class PricingModuleService< ) } - @InjectTransactionManager("baseRepository_") - async delete( - ids: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.priceSetService_.delete(ids, sharedContext) - } - - @InjectManager("baseRepository_") - async retrieveMoneyAmount( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const moneyAmount = await this.moneyAmountService_.retrieve( - id, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - moneyAmount, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listMoneyAmounts( - filters: PricingTypes.FilterableMoneyAmountProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const moneyAmounts = await this.moneyAmountService_.list( - filters, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - moneyAmounts, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCountMoneyAmounts( - filters: PricingTypes.FilterableMoneyAmountProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PricingTypes.MoneyAmountDTO[], number]> { - const [moneyAmounts, count] = await this.moneyAmountService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - moneyAmounts, - { - populate: true, - } - ), - count, - ] - } - @InjectTransactionManager("baseRepository_") async createMoneyAmounts( data: PricingTypes.CreateMoneyAmountDTO[], @@ -832,7 +723,7 @@ export default class PricingModuleService< sharedContext ) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( moneyAmounts, { populate: true, @@ -850,7 +741,7 @@ export default class PricingModuleService< sharedContext ) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( moneyAmounts, { populate: true, @@ -858,109 +749,6 @@ export default class PricingModuleService< ) } - @InjectTransactionManager("baseRepository_") - async deleteMoneyAmounts( - ids: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.moneyAmountService_.delete(ids, sharedContext) - } - - @InjectTransactionManager("baseRepository_") - async softDeleteMoneyAmounts( - ids: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.moneyAmountService_.softDelete(ids, sharedContext) - } - - @InjectTransactionManager("baseRepository_") - async restoreDeletedMoneyAmounts< - TReturnableLinkableKeys extends string = Lowercase< - keyof typeof LinkableKeys - > - >( - ids: string[], - { returnLinkableKeys }: RestoreReturn = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise, string[]> | void> { - const [_, cascadedEntitiesMap] = await this.moneyAmountService_.restore( - ids, - sharedContext - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - - @InjectManager("baseRepository_") - async retrieveCurrency( - code: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const currency = await this.currencyService_.retrieve( - code, - config, - sharedContext - ) - - return this.baseRepository_.serialize(currency, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async listCurrencies( - filters: PricingTypes.FilterableCurrencyProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const currencies = await this.currencyService_.list( - filters, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - currencies, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCountCurrencies( - filters: PricingTypes.FilterableCurrencyProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PricingTypes.CurrencyDTO[], number]> { - const [currencies, count] = await this.currencyService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - currencies, - { - populate: true, - } - ), - count, - ] - } - @InjectTransactionManager("baseRepository_") async createCurrencies( data: PricingTypes.CreateCurrencyDTO[], @@ -968,7 +756,7 @@ export default class PricingModuleService< ) { const currencies = await this.currencyService_.create(data, sharedContext) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( currencies, { populate: true, @@ -983,7 +771,7 @@ export default class PricingModuleService< ) { const currencies = await this.currencyService_.update(data, sharedContext) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( currencies, { populate: true, @@ -991,74 +779,6 @@ export default class PricingModuleService< ) } - @InjectTransactionManager("baseRepository_") - async deleteCurrencies( - currencyCodes: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.currencyService_.delete(currencyCodes, sharedContext) - } - - @InjectManager("baseRepository_") - async retrieveRuleType( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const ruleType = await this.ruleTypeService_.retrieve( - id, - config, - sharedContext - ) - - return this.baseRepository_.serialize(ruleType, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async listRuleTypes( - filters: PricingTypes.FilterableRuleTypeProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const ruleTypes = await this.ruleTypeService_.list( - filters, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - ruleTypes, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCountRuleTypes( - filters: PricingTypes.FilterableRuleTypeProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PricingTypes.RuleTypeDTO[], number]> { - const [ruleTypes, count] = await this.ruleTypeService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - ruleTypes, - { - populate: true, - } - ), - count, - ] - } - @InjectTransactionManager("baseRepository_") async createRuleTypes( data: PricingTypes.CreateRuleTypeDTO[], @@ -1066,7 +786,7 @@ export default class PricingModuleService< ): Promise { const ruleTypes = await this.ruleTypeService_.create(data, sharedContext) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( ruleTypes, { populate: true, @@ -1081,7 +801,7 @@ export default class PricingModuleService< ): Promise { const ruleTypes = await this.ruleTypeService_.update(data, sharedContext) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( ruleTypes, { populate: true, @@ -1089,118 +809,6 @@ export default class PricingModuleService< ) } - @InjectTransactionManager("baseRepository_") - async deleteRuleTypes( - ruleTypeIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.ruleTypeService_.delete(ruleTypeIds, sharedContext) - } - - @InjectManager("baseRepository_") - async retrievePriceSetMoneyAmountRules( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const record = await this.priceSetMoneyAmountRulesService_.retrieve( - id, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - record, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listPriceSetMoneyAmountRules( - filters: PricingTypes.FilterablePriceSetMoneyAmountRulesProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const records = await this.priceSetMoneyAmountRulesService_.list( - filters, - config, - sharedContext - ) - - return this.baseRepository_.serialize< - PricingTypes.PriceSetMoneyAmountRulesDTO[] - >(records, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async listAndCountPriceSetMoneyAmountRules( - filters: PricingTypes.FilterablePriceSetMoneyAmountRulesProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PricingTypes.PriceSetMoneyAmountRulesDTO[], number]> { - const [records, count] = - await this.priceSetMoneyAmountRulesService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize< - PricingTypes.PriceSetMoneyAmountRulesDTO[] - >(records, { - populate: true, - }), - count, - ] - } - - @InjectManager("baseRepository_") - async listPriceSetMoneyAmounts( - filters: PricingTypes.FilterablePriceSetMoneyAmountProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const records = await this.priceSetMoneyAmountService_.list( - filters, - config, - sharedContext - ) - - return this.baseRepository_.serialize< - PricingTypes.PriceSetMoneyAmountDTO[] - >(records, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async listAndCountPriceSetMoneyAmounts( - filters: PricingTypes.FilterablePriceSetMoneyAmountProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PricingTypes.PriceSetMoneyAmountDTO[], number]> { - const [records, count] = - await this.priceSetMoneyAmountService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize< - PricingTypes.PriceSetMoneyAmountDTO[] - >(records, { - populate: true, - }), - count, - ] - } - @InjectTransactionManager("baseRepository_") async createPriceSetMoneyAmountRules( data: PricingTypes.CreatePriceSetMoneyAmountRulesDTO[], @@ -1211,7 +819,7 @@ export default class PricingModuleService< sharedContext ) - return this.baseRepository_.serialize< + return await this.baseRepository_.serialize< PricingTypes.PriceSetMoneyAmountRulesDTO[] >(records, { populate: true, @@ -1228,84 +836,13 @@ export default class PricingModuleService< sharedContext ) - return this.baseRepository_.serialize< + return await this.baseRepository_.serialize< PricingTypes.PriceSetMoneyAmountRulesDTO[] >(records, { populate: true, }) } - @InjectTransactionManager("baseRepository_") - async deletePriceSetMoneyAmountRules( - ids: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.priceSetMoneyAmountRulesService_.delete(ids, sharedContext) - } - - @InjectManager("baseRepository_") - async retrievePriceRule( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const priceRule = await this.priceRuleService_.retrieve( - id, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - priceRule, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listPriceRules( - filters: PricingTypes.FilterablePriceRuleProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const priceRules = await this.priceRuleService_.list( - filters, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - priceRules, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCountPriceRules( - filters: PricingTypes.FilterablePriceRuleProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PricingTypes.PriceRuleDTO[], number]> { - const [priceRules, count] = await this.priceRuleService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - priceRules, - { - populate: true, - } - ), - count, - ] - } - @InjectTransactionManager("baseRepository_") async createPriceRules( data: PricingTypes.CreatePriceRuleDTO[], @@ -1316,7 +853,7 @@ export default class PricingModuleService< sharedContext ) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( priceRules, { populate: true, @@ -1331,7 +868,7 @@ export default class PricingModuleService< ): Promise { const priceRules = await this.priceRuleService_.update(data, sharedContext) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( priceRules, { populate: true, @@ -1339,77 +876,6 @@ export default class PricingModuleService< ) } - @InjectTransactionManager("baseRepository_") - async deletePriceRules( - priceRuleIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.priceRuleService_.delete(priceRuleIds, sharedContext) - } - - @InjectManager("baseRepository_") - async retrievePriceList( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const priceList = await this.priceListService_.retrieve( - id, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - priceList, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listPriceLists( - filters: PricingTypes.FilterablePriceListProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const priceLists = await this.priceListService_.list( - filters, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - priceLists, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCountPriceLists( - filters: PricingTypes.FilterablePriceListProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PricingTypes.PriceListDTO[], number]> { - const [priceLists, count] = await this.priceListService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - priceLists, - { - populate: true, - } - ), - count, - ] - } - @InjectManager("baseRepository_") async createPriceLists( data: PricingTypes.CreatePriceListDTO[], @@ -1417,7 +883,7 @@ export default class PricingModuleService< ): Promise { const priceLists = await this.createPriceLists_(data, sharedContext) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( priceLists, { populate: true, @@ -1568,7 +1034,7 @@ export default class PricingModuleService< ): Promise { const priceLists = await this.updatePriceLists_(data, sharedContext) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( priceLists, { populate: true, @@ -1694,77 +1160,6 @@ export default class PricingModuleService< return updatedPriceLists } - @InjectTransactionManager("baseRepository_") - async deletePriceLists( - priceListIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.priceListService_.delete(priceListIds, sharedContext) - } - - @InjectManager("baseRepository_") - async retrievePriceListRule( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const priceList = await this.priceListRuleService_.retrieve( - id, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - priceList, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listPriceListRules( - filters: PricingTypes.FilterablePriceListRuleProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const priceLists = await this.priceListRuleService_.list( - filters, - config, - sharedContext - ) - - return this.baseRepository_.serialize( - priceLists, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCountPriceListRules( - filters: PricingTypes.FilterablePriceListRuleProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PricingTypes.PriceListRuleDTO[], number]> { - const [priceLists, count] = await this.priceListRuleService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - priceLists, - { - populate: true, - } - ), - count, - ] - } - @InjectManager("baseRepository_") async createPriceListRules( data: PricingTypes.CreatePriceListRuleDTO[], @@ -1772,7 +1167,7 @@ export default class PricingModuleService< ): Promise { const priceLists = await this.createPriceListRules_(data, sharedContext) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( priceLists, { populate: true, @@ -1798,7 +1193,7 @@ export default class PricingModuleService< sharedContext ) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( priceLists, { populate: true, @@ -1806,14 +1201,6 @@ export default class PricingModuleService< ) } - @InjectTransactionManager("baseRepository_") - async deletePriceListRules( - priceListRuleIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.priceListRuleService_.delete(priceListRuleIds, sharedContext) - } - @InjectManager("baseRepository_") async addPriceListPrices( data: PricingTypes.AddPriceListPricesDTO[], @@ -2085,14 +1472,16 @@ export default class PricingModuleService< await Promise.all([ this.priceListRuleValueService_.delete( - priceListValuesToDelete.map((p) => p.id) + priceListValuesToDelete.map((p) => p.id), + sharedContext ), this.priceListRuleValueService_.create( - priceListRuleValuesToCreate as CreatePriceListRuleValueDTO[] + priceListRuleValuesToCreate as ServiceTypes.CreatePriceListRuleValueDTO[], + sharedContext ), ]) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( priceLists, { populate: true, @@ -2154,7 +1543,7 @@ export default class PricingModuleService< await this.priceListRuleService_.delete(idsToDelete) - return this.baseRepository_.serialize( + return await this.baseRepository_.serialize( priceLists, { populate: true, diff --git a/packages/pricing/src/services/rule-type.ts b/packages/pricing/src/services/rule-type.ts index 9bd78752c0..147754ad5a 100644 --- a/packages/pricing/src/services/rule-type.ts +++ b/packages/pricing/src/services/rule-type.ts @@ -14,17 +14,9 @@ type InjectedDependencies = { export default class RuleTypeService< TEntity extends RuleType = RuleType -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ServiceTypes.CreateRuleTypeDTO - update: ServiceTypes.UpdateRuleTypeDTO - }, - { - list: ServiceTypes.FilterableRuleTypeProps - listAndCount: ServiceTypes.FilterableRuleTypeProps - } ->(RuleType) { +> extends ModulesSdkUtils.internalModuleServiceFactory( + RuleType +) { protected readonly ruleTypeRepository_: DAL.RepositoryService constructor({ ruleTypeRepository }: InjectedDependencies) { @@ -33,21 +25,45 @@ export default class RuleTypeService< this.ruleTypeRepository_ = ruleTypeRepository } - @InjectTransactionManager("ruleTypeRepository_") - async create( + create( + data: ServiceTypes.CreateRuleTypeDTO, + sharedContext: Context + ): Promise + create( data: ServiceTypes.CreateRuleTypeDTO[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - validateRuleAttributes(data.map((d) => d.rule_attribute)) - return await this.ruleTypeRepository_.create(data, sharedContext) - } + sharedContext: Context + ): Promise @InjectTransactionManager("ruleTypeRepository_") - async update( - data: ServiceTypes.UpdateRuleTypeDTO[], + async create( + data: ServiceTypes.CreateRuleTypeDTO | ServiceTypes.CreateRuleTypeDTO[], @MedusaContext() sharedContext: Context = {} - ): Promise { - validateRuleAttributes(data.map((d) => d.rule_attribute)) - return await this.ruleTypeRepository_.update(data, sharedContext) + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + validateRuleAttributes(data_.map((d) => d.rule_attribute)) + return await super.create(data, sharedContext) + } + + // @ts-ignore + update( + data: ServiceTypes.UpdateRuleTypeDTO[], + sharedContext: Context + ): Promise + // @ts-ignore + update( + data: ServiceTypes.UpdateRuleTypeDTO, + sharedContext: Context + ): Promise + + @InjectTransactionManager("ruleTypeRepository_") + // TODO: add support for selector? and then rm ts ignore + // @ts-ignore + async update( + data: ServiceTypes.UpdateRuleTypeDTO | ServiceTypes.UpdateRuleTypeDTO[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + validateRuleAttributes(data_.map((d) => d.rule_attribute)) + return await super.update(data, sharedContext) } } diff --git a/packages/pricing/src/types/repositories/index.ts b/packages/pricing/src/types/repositories/index.ts index 117d7bda46..a1e262b975 100644 --- a/packages/pricing/src/types/repositories/index.ts +++ b/packages/pricing/src/types/repositories/index.ts @@ -1,44 +1,3 @@ -import { - Currency, - MoneyAmount, - PriceList, - PriceListRule, - PriceListRuleValue, - PriceRule, - PriceSet, - PriceSetMoneyAmount, - PriceSetMoneyAmountRules, - PriceSetRuleType, - RuleType, -} from "@models" -import { DAL } from "@medusajs/types" -import { CreateCurrencyDTO, UpdateCurrencyDTO } from "./currency" -import { CreateMoneyAmountDTO, UpdateMoneyAmountDTO } from "./money-amount" -import { - CreatePriceListRuleValueDTO, - UpdatePriceListRuleValueDTO, -} from "./price-list-rule-value" -import { - CreatePriceListRuleDTO, - UpdatePriceListRuleDTO, -} from "./price-list-rule" -import { CreatePriceListDTO, UpdatePriceListDTO } from "./price-list" -import { CreatePriceRuleDTO, UpdatePriceRuleDTO } from "./price-rule" -import { - CreatePriceSetMoneyAmountRulesDTO, - UpdatePriceSetMoneyAmountRulesDTO, -} from "./price-set-money-amount-rules" -import { - CreatePriceSetMoneyAmountDTO, - UpdatePriceSetMoneyAmountDTO, -} from "./price-set-money-amount" -import { - CreatePriceSetRuleTypeDTO, - UpdatePriceSetRuleTypeDTO, -} from "./price-set-rule-type" -import { CreatePriceSetDTO, UpdatePriceSetDTO } from "./price-set" -import { CreateRuleTypeDTO, UpdateRuleTypeDTO } from "./rule-type" - export * from "./currency" export * from "./money-amount" export * from "./price-list-rule-value" @@ -50,119 +9,3 @@ export * from "./price-set-money-amount" export * from "./price-set-rule-type" export * from "./price-set" export * from "./rule-type" - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ICurrencyRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreateCurrencyDTO - update: UpdateCurrencyDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IMoneyAmountRepository< - TEntity extends MoneyAmount = MoneyAmount -> extends DAL.RepositoryService< - TEntity, - { - create: CreateMoneyAmountDTO - update: UpdateMoneyAmountDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPriceListRuleValueRepository< - TEntity extends PriceListRuleValue = PriceListRuleValue -> extends DAL.RepositoryService< - TEntity, - { - create: CreatePriceListRuleValueDTO - update: UpdatePriceListRuleValueDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPriceListRuleRepository< - TEntity extends PriceListRule = PriceListRule -> extends DAL.RepositoryService< - TEntity, - { - create: CreatePriceListRuleDTO - update: UpdatePriceListRuleDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPriceListRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreatePriceListDTO - update: UpdatePriceListDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPriceRuleRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreatePriceRuleDTO - update: UpdatePriceRuleDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPriceSetMoneyAmountRulesRepository< - TEntity extends PriceSetMoneyAmountRules = PriceSetMoneyAmountRules -> extends DAL.RepositoryService< - TEntity, - { - create: CreatePriceSetMoneyAmountRulesDTO - update: UpdatePriceSetMoneyAmountRulesDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPriceSetMoneyAmountRepository< - TEntity extends PriceSetMoneyAmount = PriceSetMoneyAmount -> extends DAL.RepositoryService< - TEntity, - { - create: CreatePriceSetMoneyAmountDTO - update: UpdatePriceSetMoneyAmountDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPriceSetRuleTypeRepository< - TEntity extends PriceSetRuleType = PriceSetRuleType -> extends DAL.RepositoryService< - TEntity, - { - create: CreatePriceSetRuleTypeDTO - update: UpdatePriceSetRuleTypeDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPriceSetRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreatePriceSetDTO - update: UpdatePriceSetDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IRuleTypeRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreateRuleTypeDTO - update: UpdateRuleTypeDTO - } - > {} diff --git a/packages/product/integration-tests/__tests__/services/product-collection/index.ts b/packages/product/integration-tests/__tests__/services/product-collection/index.ts index 98dc40be6c..0f415c00c2 100644 --- a/packages/product/integration-tests/__tests__/services/product-collection/index.ts +++ b/packages/product/integration-tests/__tests__/services/product-collection/index.ts @@ -240,7 +240,7 @@ describe("Product collection Service", () => { error = e } - expect(error.message).toEqual('"productCollectionId" must be defined') + expect(error.message).toEqual("productCollection - id must be defined") }) it("should return collection based on config select param", async () => { diff --git a/packages/product/integration-tests/__tests__/services/product-module-service/products.spec.ts b/packages/product/integration-tests/__tests__/services/product-module-service/products.spec.ts index 98bbc6418a..e1d9506abd 100644 --- a/packages/product/integration-tests/__tests__/services/product-module-service/products.spec.ts +++ b/packages/product/integration-tests/__tests__/services/product-module-service/products.spec.ts @@ -796,7 +796,23 @@ describe("ProductModuleService products", function () { const products = await module.create([data]) + let retrievedProducts = await module.list({ id: products[0].id }) + + expect(retrievedProducts).toHaveLength(1) + expect(retrievedProducts[0].deleted_at).toBeNull() + await module.softDelete([products[0].id]) + + retrievedProducts = await module.list( + { id: products[0].id }, + { + withDeleted: true, + } + ) + + expect(retrievedProducts).toHaveLength(1) + expect(retrievedProducts[0].deleted_at).not.toBeNull() + await module.restore([products[0].id]) const deletedProducts = await module.list( diff --git a/packages/product/integration-tests/__tests__/services/product-option/index.ts b/packages/product/integration-tests/__tests__/services/product-option/index.ts index 3c0a26c0e4..6f7e05b14e 100644 --- a/packages/product/integration-tests/__tests__/services/product-option/index.ts +++ b/packages/product/integration-tests/__tests__/services/product-option/index.ts @@ -205,7 +205,7 @@ describe("ProductOption Service", () => { error = e } - expect(error.message).toEqual('"productOptionId" must be defined') + expect(error.message).toEqual("productOption - id must be defined") }) it("should return option based on config select param", async () => { diff --git a/packages/product/integration-tests/__tests__/services/product-tag/index.ts b/packages/product/integration-tests/__tests__/services/product-tag/index.ts index c0a6ebe557..178f40a7e6 100644 --- a/packages/product/integration-tests/__tests__/services/product-tag/index.ts +++ b/packages/product/integration-tests/__tests__/services/product-tag/index.ts @@ -237,7 +237,7 @@ describe("ProductTag Service", () => { error = e } - expect(error.message).toEqual('"productTagId" must be defined') + expect(error.message).toEqual("productTag - id must be defined") }) it("should return tag based on config select param", async () => { diff --git a/packages/product/integration-tests/__tests__/services/product-type/index.ts b/packages/product/integration-tests/__tests__/services/product-type/index.ts index 9a878d308e..da07bc92fb 100644 --- a/packages/product/integration-tests/__tests__/services/product-type/index.ts +++ b/packages/product/integration-tests/__tests__/services/product-type/index.ts @@ -199,7 +199,7 @@ describe("ProductType Service", () => { error = e } - expect(error.message).toEqual('"productTypeId" must be defined') + expect(error.message).toEqual("productType - id must be defined") }) it("should return type based on config select param", async () => { diff --git a/packages/product/integration-tests/__tests__/services/product-variant/index.ts b/packages/product/integration-tests/__tests__/services/product-variant/index.ts index 8f608d6dd8..43c8229e01 100644 --- a/packages/product/integration-tests/__tests__/services/product-variant/index.ts +++ b/packages/product/integration-tests/__tests__/services/product-variant/index.ts @@ -320,7 +320,7 @@ describe("ProductVariant Service", () => { error = e } - expect(error.message).toEqual('"productVariantId" must be defined') + expect(error.message).toEqual("productVariant - id must be defined") }) }) }) diff --git a/packages/product/integration-tests/__tests__/services/product/index.ts b/packages/product/integration-tests/__tests__/services/product/index.ts index c4aaaddb1c..b64de6ae6f 100644 --- a/packages/product/integration-tests/__tests__/services/product/index.ts +++ b/packages/product/integration-tests/__tests__/services/product/index.ts @@ -78,7 +78,7 @@ describe("Product Service", () => { error = e } - expect(error.message).toEqual('"productId" must be defined') + expect(error.message).toEqual("product - id must be defined") }) it("should throw an error when product with id does not exist", async () => { @@ -217,7 +217,7 @@ describe("Product Service", () => { error = e } - expect(error.message).toEqual(`Product with id "undefined" not found`) + expect(error.message).toEqual(`Product with id "" not found`) let result = await service.retrieve(productOne.id) diff --git a/packages/product/src/models/product.ts b/packages/product/src/models/product.ts index 2415a148cb..5113c51c22 100644 --- a/packages/product/src/models/product.ts +++ b/packages/product/src/models/product.ts @@ -144,7 +144,7 @@ class Product { @ManyToMany(() => ProductCategory, "products", { owner: true, pivotTable: "product_category_product", - cascade: ["soft-remove"] as any, + // TODO: rm cascade: ["soft-remove"] as any, }) categories = new Collection(this) diff --git a/packages/product/src/repositories/product-image.ts b/packages/product/src/repositories/product-image.ts index 90eb181c0c..c37bbf7b43 100644 --- a/packages/product/src/repositories/product-image.ts +++ b/packages/product/src/repositories/product-image.ts @@ -14,6 +14,6 @@ export class ProductImageRepository extends DALUtils.mikroOrmBaseRepositoryFacto async upsert(urls: string[], context: Context = {}): Promise { const data = urls.map((url) => ({ url })) - return await super.upsert(data, context) + return (await super.upsert(data, context)) as Image[] } } diff --git a/packages/product/src/repositories/product.ts b/packages/product/src/repositories/product.ts index eb430a06d4..0ff5ebbd2b 100644 --- a/packages/product/src/repositories/product.ts +++ b/packages/product/src/repositories/product.ts @@ -17,8 +17,8 @@ import { DALUtils, isDefined, MedusaError, - promiseAll, ProductUtils, + promiseAll, } from "@medusajs/utils" import { ProductServiceTypes } from "../types/services" @@ -118,7 +118,10 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory[], + data: { + entity: Product + update: WithRequiredProperty + }[], context: Context = {} ): Promise { let categoryIds: string[] = [] @@ -128,7 +131,7 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory(context) - data.forEach((productData) => { + data.forEach(({ update: productData }) => { categoryIds = categoryIds.concat( productData?.categories?.map((c) => c.id) || [] ) @@ -144,16 +147,6 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory updateData.id), - }, - { - populate: ["tags", "categories"], - } - ) - const collectionsToAssign = collectionIds.length ? await manager.find(ProductCollection, { id: collectionIds, @@ -195,11 +188,11 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory( - productsToUpdate.map((product) => [product.id, product]) + data.map(({ entity }) => [entity.id, entity]) ) const products = await promiseAll( - data.map(async (updateData) => { + data.map(async ({ update: updateData }) => { const product = productsToUpdateMap.get(updateData.id) if (!product) { diff --git a/packages/product/src/services/__fixtures__/product.ts b/packages/product/src/services/__fixtures__/product.ts index ec32ccbb28..7a185e0e24 100644 --- a/packages/product/src/services/__fixtures__/product.ts +++ b/packages/product/src/services/__fixtures__/product.ts @@ -1,11 +1,8 @@ -import { asClass, asValue, createContainer } from "awilix" -import { ProductService } from "@services" +import { asValue } from "awilix" export const nonExistingProductId = "non-existing-id" -export const mockContainer = createContainer() -mockContainer.register({ - transaction: asValue(async (task) => await task()), +export const productRepositoryMock = { productRepository: asValue({ find: jest.fn().mockImplementation(async ({ where: { id } }) => { if (id === nonExistingProductId) { @@ -17,5 +14,4 @@ mockContainer.register({ findAndCount: jest.fn().mockResolvedValue([[], 0]), getFreshManager: jest.fn().mockResolvedValue({}), }), - productService: asClass(ProductService), -}) +} diff --git a/packages/product/src/services/__tests__/product.spec.ts b/packages/product/src/services/__tests__/product.spec.ts index 6d2820a19e..fb1a6819d3 100644 --- a/packages/product/src/services/__tests__/product.spec.ts +++ b/packages/product/src/services/__tests__/product.spec.ts @@ -1,13 +1,28 @@ -import { mockContainer, nonExistingProductId } from "../__fixtures__/product" +import { + nonExistingProductId, + productRepositoryMock, +} from "../__fixtures__/product" +import { createMedusaContainer } from "@medusajs/utils" +import { asValue } from "awilix" +import ContainerLoader from "../../loaders/container" describe("Product service", function () { - beforeEach(function () { + let container + + beforeEach(async function () { jest.clearAllMocks() + + container = createMedusaContainer() + container.register("manager", asValue({})) + + await ContainerLoader({ container }) + + container.register(productRepositoryMock) }) it("should retrieve a product", async function () { - const productService = mockContainer.resolve("productService") - const productRepository = mockContainer.resolve("productRepository") + const productService = container.resolve("productService") + const productRepository = container.resolve("productRepository") const productId = "existing-product" await productService.retrieve(productId) @@ -30,8 +45,8 @@ describe("Product service", function () { }) it("should fail to retrieve a product", async function () { - const productService = mockContainer.resolve("productService") - const productRepository = mockContainer.resolve("productRepository") + const productService = container.resolve("productService") + const productRepository = container.resolve("productRepository") const err = await productService .retrieve(nonExistingProductId) @@ -59,8 +74,8 @@ describe("Product service", function () { }) it("should list products", async function () { - const productService = mockContainer.resolve("productService") - const productRepository = mockContainer.resolve("productRepository") + const productService = container.resolve("productService") + const productRepository = container.resolve("productRepository") const filters = {} const config = { @@ -85,8 +100,8 @@ describe("Product service", function () { }) it("should list products with filters", async function () { - const productService = mockContainer.resolve("productService") - const productRepository = mockContainer.resolve("productRepository") + const productService = container.resolve("productService") + const productRepository = container.resolve("productRepository") const filters = { tags: { @@ -123,8 +138,8 @@ describe("Product service", function () { }) it("should list products with filters and relations", async function () { - const productService = mockContainer.resolve("productService") - const productRepository = mockContainer.resolve("productRepository") + const productService = container.resolve("productService") + const productRepository = container.resolve("productRepository") const filters = { tags: { @@ -161,8 +176,8 @@ describe("Product service", function () { }) it("should list and count the products with filters and relations", async function () { - const productService = mockContainer.resolve("productService") - const productRepository = mockContainer.resolve("productRepository") + const productService = container.resolve("productService") + const productRepository = container.resolve("productRepository") const filters = { tags: { diff --git a/packages/product/src/services/index.ts b/packages/product/src/services/index.ts index dc485567aa..efc05645e7 100644 --- a/packages/product/src/services/index.ts +++ b/packages/product/src/services/index.ts @@ -6,5 +6,3 @@ export { default as ProductTagService } from "./product-tag" export { default as ProductVariantService } from "./product-variant" export { default as ProductTypeService } from "./product-type" export { default as ProductOptionService } from "./product-option" -export { default as ProductImageService } from "./product-image" -export { default as ProductOptionValueService } from "./product-option-value" diff --git a/packages/product/src/services/product-collection.ts b/packages/product/src/services/product-collection.ts index 5ace64dea3..4c51ece1e3 100644 --- a/packages/product/src/services/product-collection.ts +++ b/packages/product/src/services/product-collection.ts @@ -7,14 +7,7 @@ import { } from "@medusajs/utils" import { ProductCollection } from "@models" -import { - IProductCollectionRepository, - ProductCollectionServiceTypes, -} from "@types" -import { - CreateProductCollection, - UpdateProductCollection, -} from "../types/services/product-collection" +import { ProductCollectionServiceTypes } from "@types" type InjectedDependencies = { productCollectionRepository: DAL.RepositoryService @@ -22,15 +15,11 @@ type InjectedDependencies = { export default class ProductCollectionService< TEntity extends ProductCollection = ProductCollection -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateProductCollection - update: UpdateProductCollection - } ->(ProductCollection) { +> extends ModulesSdkUtils.internalModuleServiceFactory( + ProductCollection +) { // eslint-disable-next-line max-len - protected readonly productCollectionRepository_: IProductCollectionRepository + protected readonly productCollectionRepository_: DAL.RepositoryService constructor(container: InjectedDependencies) { super(container) @@ -38,9 +27,9 @@ export default class ProductCollectionService< } @InjectManager("productCollectionRepository_") - async list( + async list( filters: ProductTypes.FilterableProductCollectionProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { return await this.productCollectionRepository_.find( @@ -50,9 +39,9 @@ export default class ProductCollectionService< } @InjectManager("productCollectionRepository_") - async listAndCount( + async listAndCount( filters: ProductTypes.FilterableProductCollectionProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[TEntity[], number]> { return await this.productCollectionRepository_.findAndCount( @@ -61,11 +50,9 @@ export default class ProductCollectionService< ) } - protected buildListQueryOptions< - TEntityMethod = ProductTypes.ProductCollectionDTO - >( + protected buildListQueryOptions( filters: ProductTypes.FilterableProductCollectionProps = {}, - config: FindConfig = {} + config: FindConfig = {} ): DAL.FindOptions { const queryOptions = ModulesSdkUtils.buildQuery(filters, config) @@ -80,12 +67,24 @@ export default class ProductCollectionService< return queryOptions } + create( + data: ProductCollectionServiceTypes.CreateProductCollection, + context?: Context + ): Promise + create( + data: ProductCollectionServiceTypes.CreateProductCollection[], + context?: Context + ): Promise + @InjectTransactionManager("productCollectionRepository_") async create( - data: ProductCollectionServiceTypes.CreateProductCollection[], + data: + | ProductCollectionServiceTypes.CreateProductCollection + | ProductCollectionServiceTypes.CreateProductCollection[], context: Context = {} - ): Promise { - const productCollections = data.map((collectionData) => { + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + const productCollections = data_.map((collectionData) => { if (collectionData.product_ids) { collectionData.products = collectionData.product_ids @@ -98,12 +97,27 @@ export default class ProductCollectionService< return super.create(productCollections, context) } - @InjectTransactionManager("productCollectionRepository_") - async update( + // @ts-ignore + update( + data: ProductCollectionServiceTypes.UpdateProductCollection, + context?: Context + ): Promise + // @ts-ignore + update( data: ProductCollectionServiceTypes.UpdateProductCollection[], + context?: Context + ): Promise + + @InjectTransactionManager("productCollectionRepository_") + // @ts-ignore Do not implement all the expected overloads, see if we must do it + async update( + data: + | ProductCollectionServiceTypes.UpdateProductCollection + | ProductCollectionServiceTypes.UpdateProductCollection[], context: Context = {} - ): Promise { - const productCollections = data.map((collectionData) => { + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + const productCollections = data_.map((collectionData) => { if (collectionData.product_ids) { collectionData.products = collectionData.product_ids diff --git a/packages/product/src/services/product-image.ts b/packages/product/src/services/product-image.ts deleted file mode 100644 index 50ab03044e..0000000000 --- a/packages/product/src/services/product-image.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Image } from "@models" -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" - -type InjectedDependencies = { - productImageRepository: DAL.RepositoryService -} - -export default class ProductImageService< - TEntity extends Image = Image -> extends ModulesSdkUtils.abstractServiceFactory( - Image -) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/product/src/services/product-module-service.ts b/packages/product/src/services/product-module-service.ts index 6285fd4773..84febcf50e 100644 --- a/packages/product/src/services/product-module-service.ts +++ b/packages/product/src/services/product-module-service.ts @@ -2,13 +2,11 @@ import { Context, CreateProductOnlyDTO, DAL, - FindConfig, IEventBusModuleService, InternalModuleDeclaration, ModuleJoinerConfig, + ModulesSdkTypes, ProductTypes, - RestoreReturn, - SoftDeleteReturn, } from "@medusajs/types" import { Image, @@ -25,22 +23,12 @@ import { ProductCategoryService, ProductCollectionService, ProductOptionService, - ProductOptionValueService, ProductService, ProductTagService, ProductTypeService, ProductVariantService, } from "@services" -import ProductImageService from "./product-image" - -import { - ProductCategoryServiceTypes, - ProductCollectionServiceTypes, - ProductServiceTypes, - ProductVariantServiceTypes, -} from "@types" - import { arrayDifference, groupBy, @@ -49,25 +37,24 @@ import { isDefined, isString, kebabCase, - mapObjectTo, MedusaContext, MedusaError, + ModulesSdkUtils, promiseAll, } from "@medusajs/utils" +import { entityNameToLinkableKeysMap, joinerConfig } from "./../joiner-config" import { ProductEventData, ProductEvents } from "../types/services/product" import { ProductCategoryEventData, ProductCategoryEvents, } from "../types/services/product-category" import { - CreateProductOptionValueDTO, - UpdateProductOptionValueDTO, -} from "../types/services/product-option-value" -import { - entityNameToLinkableKeysMap, - joinerConfig, - LinkableKeys, -} from "./../joiner-config" + ProductCategoryServiceTypes, + ProductCollectionServiceTypes, + ProductOptionValueServiceTypes, + ProductServiceTypes, + ProductVariantServiceTypes, +} from "@types" type InjectedDependencies = { baseRepository: DAL.RepositoryService @@ -76,24 +63,70 @@ type InjectedDependencies = { productTagService: ProductTagService productCategoryService: ProductCategoryService productCollectionService: ProductCollectionService - productImageService: ProductImageService + productImageService: ModulesSdkTypes.InternalModuleService productTypeService: ProductTypeService productOptionService: ProductOptionService - productOptionValueService: ProductOptionValueService + productOptionValueService: ModulesSdkTypes.InternalModuleService eventBusModuleService?: IEventBusModuleService } +const generateMethodForModels = [ + { model: ProductCategory, singular: "Category", plural: "Categories" }, + { model: ProductCollection, singular: "Collection", plural: "Collections" }, + { model: ProductOption, singular: "Option", plural: "Options" }, + { model: ProductTag, singular: "Tag", plural: "Tags" }, + { model: ProductType, singular: "Type", plural: "Types" }, + { model: ProductVariant, singular: "Variant", plural: "Variants" }, +] + export default class ProductModuleService< - TProduct extends Product = Product, - TProductVariant extends ProductVariant = ProductVariant, - TProductTag extends ProductTag = ProductTag, - TProductCollection extends ProductCollection = ProductCollection, - TProductCategory extends ProductCategory = ProductCategory, - TProductImage extends Image = Image, - TProductType extends ProductType = ProductType, - TProductOption extends ProductOption = ProductOption, - TProductOptionValue extends ProductOptionValue = ProductOptionValue -> implements ProductTypes.IProductModuleService + TProduct extends Product = Product, + TProductVariant extends ProductVariant = ProductVariant, + TProductTag extends ProductTag = ProductTag, + TProductCollection extends ProductCollection = ProductCollection, + TProductCategory extends ProductCategory = ProductCategory, + TProductImage extends Image = Image, + TProductType extends ProductType = ProductType, + TProductOption extends ProductOption = ProductOption, + TProductOptionValue extends ProductOptionValue = ProductOptionValue + > + extends ModulesSdkUtils.abstractModuleServiceFactory< + InjectedDependencies, + ProductTypes.ProductDTO, + { + ProductCategory: { + dto: ProductTypes.ProductCategoryDTO + singular: "Category" + plural: "Categories" + } + ProductCollection: { + dto: ProductTypes.ProductCollectionDTO + singular: "Collection" + plural: "Collections" + } + ProductOption: { + dto: ProductTypes.ProductOptionDTO + singular: "Option" + plural: "Options" + } + ProductTag: { + dto: ProductTypes.ProductTagDTO + singular: "Tag" + plural: "Tags" + } + ProductType: { + dto: ProductTypes.ProductTypeDTO + singular: "Type" + plural: "Types" + } + ProductVariant: { + dto: ProductTypes.ProductVariantDTO + singular: "Variant" + plural: "Variants" + } + } + >(Product, generateMethodForModels, entityNameToLinkableKeysMap) + implements ProductTypes.IProductModuleService { protected baseRepository_: DAL.RepositoryService protected readonly productService_: ProductService @@ -107,11 +140,12 @@ export default class ProductModuleService< protected readonly productTagService_: ProductTagService // eslint-disable-next-line max-len protected readonly productCollectionService_: ProductCollectionService - protected readonly productImageService_: ProductImageService + // eslint-disable-next-line max-len + protected readonly productImageService_: ModulesSdkTypes.InternalModuleService protected readonly productTypeService_: ProductTypeService protected readonly productOptionService_: ProductOptionService // eslint-disable-next-line max-len - protected readonly productOptionValueService_: ProductOptionValueService + protected readonly productOptionValueService_: ModulesSdkTypes.InternalModuleService protected readonly eventBusModuleService_?: IEventBusModuleService constructor( @@ -130,6 +164,10 @@ export default class ProductModuleService< }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { + // @ts-ignore + // eslint-disable-next-line prefer-rest-params + super(...arguments) + this.baseRepository_ = baseRepository this.productService_ = productService this.productVariantService_ = productVariantService @@ -147,96 +185,6 @@ export default class ProductModuleService< return joinerConfig } - @InjectManager("baseRepository_") - async list( - filters: ProductTypes.FilterableProductProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const products = await this.productService_.list( - filters, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(products)) - } - - @InjectManager("baseRepository_") - async retrieve( - productId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const product = await this.productService_.retrieve( - productId, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(product)) - } - - @InjectManager("baseRepository_") - async listAndCount( - filters: ProductTypes.FilterableProductProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[ProductTypes.ProductDTO[], number]> { - const [products, count] = await this.productService_.listAndCount( - filters, - config, - sharedContext - ) - - return [JSON.parse(JSON.stringify(products)), count] - } - - @InjectManager("baseRepository_") - async retrieveVariant( - productVariantId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const productVariant = await this.productVariantService_.retrieve( - productVariantId, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(productVariant)) - } - - @InjectManager("baseRepository_") - async listVariants( - filters: ProductTypes.FilterableProductVariantProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const variants = await this.productVariantService_.list( - filters, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(variants)) - } - - @InjectManager("baseRepository_") - async listAndCountVariants( - filters: ProductTypes.FilterableProductVariantProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[ProductTypes.ProductVariantDTO[], number]> { - const [variants, count] = await this.productVariantService_.listAndCount( - filters, - config, - sharedContext - ) - - return [JSON.parse(JSON.stringify(variants)), count] - } - async createVariants( data: ProductTypes.CreateProductVariantDTO[], @MedusaContext() sharedContext: Context = {} @@ -300,21 +248,6 @@ export default class ProductModuleService< return productVariants as unknown as ProductTypes.ProductVariantDTO[] } - @InjectTransactionManager("baseRepository_") - async deleteVariants( - productVariantIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.productVariantService_.delete(productVariantIds, sharedContext) - - await this.eventBusModuleService_?.emit( - productVariantIds.map((id) => ({ - eventName: ProductEvents.PRODUCT_DELETED, - data: { id }, - })) - ) - } - @InjectManager("baseRepository_") async updateVariants( data: ProductTypes.UpdateProductVariantOnlyDTO[], @@ -324,9 +257,7 @@ export default class ProductModuleService< const updatedVariants = await this.baseRepository_.serialize< ProductTypes.ProductVariantDTO[] - >(productVariants, { - populate: true, - }) + >(productVariants) return updatedVariants } @@ -357,8 +288,8 @@ export default class ProductModuleService< } const optionValuesToUpsert: ( - | CreateProductOptionValueDTO - | UpdateProductOptionValueDTO + | ProductOptionValueServiceTypes.CreateProductOptionValueDTO + | ProductOptionValueServiceTypes.UpdateProductOptionValueDTO )[] = [] const optionsValuesToDelete: string[] = [] @@ -413,11 +344,7 @@ export default class ProductModuleService< const groups = groupBy(toUpdate, "product_id") - const [, , productVariants]: [ - void, - TProductOptionValue[], - TProductVariant[][] - ] = await promiseAll([ + const [, , productVariants] = await promiseAll([ await this.productOptionValueService_.delete( optionsValuesToDelete, sharedContext @@ -440,51 +367,6 @@ export default class ProductModuleService< return productVariants.flat() } - @InjectManager("baseRepository_") - async retrieveTag( - tagId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const productTag = await this.productTagService_.retrieve( - tagId, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(productTag)) - } - - @InjectManager("baseRepository_") - async listTags( - filters: ProductTypes.FilterableProductTagProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const tags = await this.productTagService_.list( - filters, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(tags)) - } - - @InjectManager("baseRepository_") - async listAndCountTags( - filters: ProductTypes.FilterableProductTagProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[ProductTypes.ProductTagDTO[], number]> { - const [tags, count] = await this.productTagService_.listAndCount( - filters, - config, - sharedContext - ) - - return [JSON.parse(JSON.stringify(tags)), count] - } - @InjectTransactionManager("baseRepository_") async createTags( data: ProductTypes.CreateProductTagDTO[], @@ -511,59 +393,6 @@ export default class ProductModuleService< return JSON.parse(JSON.stringify(productTags)) } - @InjectTransactionManager("baseRepository_") - async deleteTags( - productTagIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.productTagService_.delete(productTagIds, sharedContext) - } - - @InjectManager("baseRepository_") - async retrieveType( - typeId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const productType = await this.productTypeService_.retrieve( - typeId, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(productType)) - } - - @InjectManager("baseRepository_") - async listTypes( - filters: ProductTypes.FilterableProductTypeProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const types = await this.productTypeService_.list( - filters, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(types)) - } - - @InjectManager("baseRepository_") - async listAndCountTypes( - filters: ProductTypes.FilterableProductTypeProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[ProductTypes.ProductTypeDTO[], number]> { - const [types, count] = await this.productTypeService_.listAndCount( - filters, - config, - sharedContext - ) - - return [JSON.parse(JSON.stringify(types)), count] - } - @InjectTransactionManager("baseRepository_") async createTypes( data: ProductTypes.CreateProductTypeDTO[], @@ -590,60 +419,6 @@ export default class ProductModuleService< return JSON.parse(JSON.stringify(productTypes)) } - @InjectTransactionManager("baseRepository_") - async deleteTypes( - productTypeIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.productTypeService_.delete(productTypeIds, sharedContext) - } - - @InjectManager("baseRepository_") - async retrieveOption( - optionId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const productOptions = await this.productOptionService_.retrieve( - optionId, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(productOptions)) - } - - @InjectManager("baseRepository_") - async listOptions( - filters: ProductTypes.FilterableProductTypeProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const productOptions = await this.productOptionService_.list( - filters, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(productOptions)) - } - - @InjectManager("baseRepository_") - async listAndCountOptions( - filters: ProductTypes.FilterableProductTypeProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[ProductTypes.ProductOptionDTO[], number]> { - const [productOptions, count] = - await this.productOptionService_.listAndCount( - filters, - config, - sharedContext - ) - - return [JSON.parse(JSON.stringify(productOptions)), count] - } - @InjectTransactionManager("baseRepository_") async createOptions( data: ProductTypes.CreateProductOptionDTO[], @@ -656,9 +431,7 @@ export default class ProductModuleService< return await this.baseRepository_.serialize< ProductTypes.ProductOptionDTO[] - >(productOptions, { - populate: true, - }) + >(productOptions) } @InjectTransactionManager("baseRepository_") @@ -673,62 +446,7 @@ export default class ProductModuleService< return await this.baseRepository_.serialize< ProductTypes.ProductOptionDTO[] - >(productOptions, { - populate: true, - }) - } - - @InjectTransactionManager("baseRepository_") - async deleteOptions( - productOptionIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.productOptionService_.delete(productOptionIds, sharedContext) - } - - @InjectManager("baseRepository_") - async retrieveCollection( - productCollectionId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const productCollection = await this.productCollectionService_.retrieve( - productCollectionId, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(productCollection)) - } - - @InjectManager("baseRepository_") - async listCollections( - filters: ProductTypes.FilterableProductCollectionProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const collections = await this.productCollectionService_.list( - filters, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(collections)) - } - - @InjectManager("baseRepository_") - async listAndCountCollections( - filters: ProductTypes.FilterableProductCollectionProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[ProductTypes.ProductCollectionDTO[], number]> { - const collections = await this.productCollectionService_.listAndCount( - filters, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(collections)) + >(productOptions) } @InjectTransactionManager("baseRepository_") @@ -777,57 +495,6 @@ export default class ProductModuleService< return JSON.parse(JSON.stringify(productCollections)) } - @InjectTransactionManager("baseRepository_") - async deleteCollections( - productCollectionIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.productCollectionService_.delete( - productCollectionIds, - sharedContext - ) - - // eslint-disable-next-line max-len - await this.eventBusModuleService_?.emit( - productCollectionIds.map((id) => ({ - eventName: - ProductCollectionServiceTypes.ProductCollectionEvents - .COLLECTION_DELETED, - data: { id }, - })) - ) - } - - @InjectManager("baseRepository_") - async retrieveCategory( - productCategoryId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const productCategory = await this.productCategoryService_.retrieve( - productCategoryId, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(productCategory)) - } - - @InjectManager("baseRepository_") - async listCategories( - filters: ProductTypes.FilterableProductCategoryProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const categories = await this.productCategoryService_.list( - filters, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(categories)) - } - @InjectTransactionManager("baseRepository_") async createCategory( data: ProductCategoryServiceTypes.CreateProductCategoryDTO, @@ -866,34 +533,6 @@ export default class ProductModuleService< return JSON.parse(JSON.stringify(productCategory)) } - @InjectTransactionManager("baseRepository_") - async deleteCategory( - categoryId: string, - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this.productCategoryService_.delete(categoryId, sharedContext) - - await this.eventBusModuleService_?.emit( - ProductCategoryEvents.CATEGORY_DELETED, - { id: categoryId } - ) - } - - @InjectManager("baseRepository_") - async listAndCountCategories( - filters: ProductTypes.FilterableProductCategoryProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[ProductTypes.ProductCategoryDTO[], number]> { - const categories = await this.productCategoryService_.listAndCount( - filters, - config, - sharedContext - ) - - return JSON.parse(JSON.stringify(categories)) - } - @InjectManager("baseRepository_") async create( data: ProductTypes.CreateProductDTO[], @@ -902,9 +541,7 @@ export default class ProductModuleService< const products = await this.create_(data, sharedContext) const createdProducts = await this.baseRepository_.serialize< ProductTypes.ProductDTO[] - >(products, { - populate: true, - }) + >(products) await this.eventBusModuleService_?.emit( createdProducts.map(({ id }) => ({ @@ -925,9 +562,7 @@ export default class ProductModuleService< const updatedProducts = await this.baseRepository_.serialize< ProductTypes.ProductDTO[] - >(products, { - populate: true, - }) + >(products) await this.eventBusModuleService_?.emit( updatedProducts.map(({ id }) => ({ @@ -1297,131 +932,15 @@ export default class ProductModuleService< } @InjectTransactionManager("baseRepository_") - async delete( - productIds: string[], + async deleteCategory( + categoryId: string, @MedusaContext() sharedContext: Context = {} ): Promise { - await this.productService_.delete(productIds, sharedContext) + await this.productCategoryService_.delete(categoryId, sharedContext) - await this.eventBusModuleService_?.emit( - productIds.map((id) => ({ - eventName: ProductEvents.PRODUCT_DELETED, - data: { id }, - })) + await this.eventBusModuleService_?.emit( + ProductCategoryEvents.CATEGORY_DELETED, + { id: categoryId } ) } - - @InjectManager("baseRepository_") - async softDelete< - TReturnableLinkableKeys extends string = Lowercase< - keyof typeof LinkableKeys - > - >( - productIds: string[], - { returnLinkableKeys }: SoftDeleteReturn = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise, string[]> | void> { - const [products, cascadedEntitiesMap] = await this.softDelete_( - productIds, - sharedContext - ) - - const softDeletedProducts = await this.baseRepository_.serialize< - ProductTypes.ProductDTO[] - >(products, { - populate: true, - }) - - await this.eventBusModuleService_?.emit( - softDeletedProducts.map(({ id }) => ({ - eventName: ProductEvents.PRODUCT_DELETED, - data: { id }, - })) - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - // Map internal table/column names to their respective external linkable keys - // eg: product.id = product_id, variant.id = variant_id - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - - @InjectTransactionManager("baseRepository_") - protected async softDelete_( - productIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise<[TProduct[], Record]> { - return await this.productService_.softDelete(productIds, sharedContext) - } - - @InjectManager("baseRepository_") - async restore< - TReturnableLinkableKeys extends string = Lowercase< - keyof typeof LinkableKeys - > - >( - productIds: string[], - { returnLinkableKeys }: RestoreReturn = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise, string[]> | void> { - const [_, cascadedEntitiesMap] = await this.restore_( - productIds, - sharedContext - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - // Map internal table/column names to their respective external linkable keys - // eg: product.id = product_id, variant.id = variant_id - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - - @InjectTransactionManager("baseRepository_") - async restoreVariants< - TReturnableLinkableKeys extends string = Lowercase< - keyof typeof LinkableKeys - > - >( - variantIds: string[], - { returnLinkableKeys }: RestoreReturn = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise, string[]> | void> { - const [_, cascadedEntitiesMap] = await this.productVariantService_.restore( - variantIds, - sharedContext - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - - @InjectTransactionManager("baseRepository_") - async restore_( - productIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise<[TProduct[], Record]> { - return await this.productService_.restore(productIds, sharedContext) - } } diff --git a/packages/product/src/services/product-option-value.ts b/packages/product/src/services/product-option-value.ts deleted file mode 100644 index 62c9bfa9f7..0000000000 --- a/packages/product/src/services/product-option-value.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ProductOptionValue } from "@models" -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { ProductOptionValueServiceTypes } from "@types" - -type InjectedDependencies = { - productOptionValueRepository: DAL.RepositoryService -} - -export default class ProductOptionValueService< - TEntity extends ProductOptionValue = ProductOptionValue -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ProductOptionValueServiceTypes.CreateProductOptionValueDTO - update: ProductOptionValueServiceTypes.UpdateProductOptionValueDTO - } ->(ProductOptionValue) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/product/src/services/product-option.ts b/packages/product/src/services/product-option.ts index 026c2a6b81..eca5140fde 100644 --- a/packages/product/src/services/product-option.ts +++ b/packages/product/src/services/product-option.ts @@ -1,7 +1,6 @@ import { ProductOption } from "@models" import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types" import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils" -import { IProductOptionRepository } from "@types" type InjectedDependencies = { productOptionRepository: DAL.RepositoryService @@ -9,14 +8,10 @@ type InjectedDependencies = { export default class ProductOptionService< TEntity extends ProductOption = ProductOption -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ProductTypes.CreateProductOptionDTO - update: ProductTypes.UpdateProductOptionDTO - } ->(ProductOption) { - protected readonly productOptionRepository_: IProductOptionRepository +> extends ModulesSdkUtils.internalModuleServiceFactory( + ProductOption +) { + protected readonly productOptionRepository_: DAL.RepositoryService constructor(container: InjectedDependencies) { super(container) @@ -24,9 +19,9 @@ export default class ProductOptionService< } @InjectManager("productOptionRepository_") - async list( + async list( filters: ProductTypes.FilterableProductOptionProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext?: Context ): Promise { return await this.productOptionRepository_.find( @@ -36,9 +31,9 @@ export default class ProductOptionService< } @InjectManager("productOptionRepository_") - async listAndCount( + async listAndCount( filters: ProductTypes.FilterableProductOptionProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext?: Context ): Promise<[TEntity[], number]> { return await this.productOptionRepository_.findAndCount( @@ -47,9 +42,9 @@ export default class ProductOptionService< ) } - private buildQueryForList( + private buildQueryForList( filters: ProductTypes.FilterableProductOptionProps = {}, - config: FindConfig = {} + config: FindConfig = {} ): DAL.FindOptions { const queryOptions = ModulesSdkUtils.buildQuery(filters, config) diff --git a/packages/product/src/services/product-tag.ts b/packages/product/src/services/product-tag.ts index a6d8522307..2111a12862 100644 --- a/packages/product/src/services/product-tag.ts +++ b/packages/product/src/services/product-tag.ts @@ -1,7 +1,6 @@ import { ProductTag } from "@models" import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types" import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils" -import { IProductTagRepository } from "@types" type InjectedDependencies = { productTagRepository: DAL.RepositoryService @@ -9,23 +8,19 @@ type InjectedDependencies = { export default class ProductTagService< TEntity extends ProductTag = ProductTag -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ProductTypes.CreateProductTagDTO - update: ProductTypes.UpdateProductTagDTO - } ->(ProductTag) { - protected readonly productTagRepository_: IProductTagRepository +> extends ModulesSdkUtils.internalModuleServiceFactory( + ProductTag +) { + protected readonly productTagRepository_: DAL.RepositoryService constructor(container: InjectedDependencies) { super(container) this.productTagRepository_ = container.productTagRepository } @InjectManager("productTagRepository_") - async list( + async list( filters: ProductTypes.FilterableProductTagProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { return await this.productTagRepository_.find( @@ -35,9 +30,9 @@ export default class ProductTagService< } @InjectManager("productTagRepository_") - async listAndCount( + async listAndCount( filters: ProductTypes.FilterableProductTagProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[TEntity[], number]> { return await this.productTagRepository_.findAndCount( @@ -46,9 +41,9 @@ export default class ProductTagService< ) } - private buildQueryForList( + private buildQueryForList( filters: ProductTypes.FilterableProductTagProps = {}, - config: FindConfig = {} + config: FindConfig = {} ): DAL.FindOptions { const queryOptions = ModulesSdkUtils.buildQuery(filters, config) diff --git a/packages/product/src/services/product-type.ts b/packages/product/src/services/product-type.ts index da5587f316..0c54344a91 100644 --- a/packages/product/src/services/product-type.ts +++ b/packages/product/src/services/product-type.ts @@ -1,7 +1,6 @@ import { ProductType } from "@models" import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types" import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils" -import { IProductTypeRepository } from "@types" type InjectedDependencies = { productTypeRepository: DAL.RepositoryService @@ -9,14 +8,10 @@ type InjectedDependencies = { export default class ProductTypeService< TEntity extends ProductType = ProductType -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ProductTypes.CreateProductTypeDTO - update: ProductTypes.UpdateProductTypeDTO - } ->(ProductType) { - protected readonly productTypeRepository_: IProductTypeRepository +> extends ModulesSdkUtils.internalModuleServiceFactory( + ProductType +) { + protected readonly productTypeRepository_: DAL.RepositoryService constructor(container: InjectedDependencies) { super(container) @@ -24,9 +19,9 @@ export default class ProductTypeService< } @InjectManager("productTypeRepository_") - async list( + async list( filters: ProductTypes.FilterableProductTypeProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { return await this.productTypeRepository_.find( @@ -36,9 +31,9 @@ export default class ProductTypeService< } @InjectManager("productTypeRepository_") - async listAndCount( + async listAndCount( filters: ProductTypes.FilterableProductTypeProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[TEntity[], number]> { return await this.productTypeRepository_.findAndCount( @@ -47,9 +42,9 @@ export default class ProductTypeService< ) } - private buildQueryForList( + private buildQueryForList( filters: ProductTypes.FilterableProductTypeProps = {}, - config: FindConfig = {} + config: FindConfig = {} ): DAL.FindOptions { const queryOptions = ModulesSdkUtils.buildQuery(filters, config) diff --git a/packages/product/src/services/product-variant.ts b/packages/product/src/services/product-variant.ts index e1a247aa1c..823886728e 100644 --- a/packages/product/src/services/product-variant.ts +++ b/packages/product/src/services/product-variant.ts @@ -7,7 +7,7 @@ import { } from "@medusajs/utils" import { Product, ProductVariant } from "@models" -import { IProductVariantRepository, ProductVariantServiceTypes } from "@types" +import { ProductVariantServiceTypes } from "@types" import ProductService from "./product" type InjectedDependencies = { @@ -18,14 +18,10 @@ type InjectedDependencies = { export default class ProductVariantService< TEntity extends ProductVariant = ProductVariant, TProduct extends Product = Product -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ProductTypes.CreateProductVariantOnlyDTO - update: ProductVariantServiceTypes.UpdateProductVariantDTO - } ->(ProductVariant) { - protected readonly productVariantRepository_: IProductVariantRepository +> extends ModulesSdkUtils.internalModuleServiceFactory( + ProductVariant +) { + protected readonly productVariantRepository_: DAL.RepositoryService protected readonly productService_: ProductService constructor({ @@ -92,8 +88,6 @@ export default class ProductVariantService< const variantsData = [...data] variantsData.forEach((variant) => Object.assign(variant, { product })) - return await this.productVariantRepository_.update(variantsData, { - transactionManager: sharedContext.transactionManager, - }) + return await super.update(variantsData, sharedContext) } } diff --git a/packages/product/src/services/product.ts b/packages/product/src/services/product.ts index 3c514c0abe..835f09b056 100644 --- a/packages/product/src/services/product.ts +++ b/packages/product/src/services/product.ts @@ -1,7 +1,6 @@ import { Context, DAL, FindConfig, ProductTypes } from "@medusajs/types" import { InjectManager, MedusaContext, ModulesSdkUtils } from "@medusajs/utils" import { Product } from "@models" -import { IProductRepository, ProductServiceTypes } from "@types" type InjectedDependencies = { productRepository: DAL.RepositoryService @@ -9,14 +8,10 @@ type InjectedDependencies = { export default class ProductService< TEntity extends Product = Product -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: ProductTypes.CreateProductOnlyDTO - update: ProductServiceTypes.UpdateProductDTO - } ->(Product) { - protected readonly productRepository_: IProductRepository +> extends ModulesSdkUtils.internalModuleServiceFactory( + Product +) { + protected readonly productRepository_: DAL.RepositoryService constructor({ productRepository }: InjectedDependencies) { // @ts-ignore @@ -27,9 +22,9 @@ export default class ProductService< } @InjectManager("productRepository_") - async list( + async list( filters: ProductTypes.FilterableProductProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { if (filters.category_id) { @@ -45,13 +40,13 @@ export default class ProductService< delete filters.category_id } - return await super.list(filters, config, sharedContext) + return await super.list(filters, config, sharedContext) } @InjectManager("productRepository_") - async listAndCount( + async listAndCount( filters: ProductTypes.FilterableProductProps = {}, - config: FindConfig = {}, + config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[TEntity[], number]> { if (filters.category_id) { @@ -67,10 +62,6 @@ export default class ProductService< delete filters.category_id } - return await super.listAndCount( - filters, - config, - sharedContext - ) + return await super.listAndCount(filters, config, sharedContext) } } diff --git a/packages/product/src/types/index.ts b/packages/product/src/types/index.ts index 051d3d01a8..2503374225 100644 --- a/packages/product/src/types/index.ts +++ b/packages/product/src/types/index.ts @@ -6,4 +6,3 @@ export type InitializeModuleInjectableDependencies = { } export * from "./services" -export * from "./repositories" diff --git a/packages/product/src/types/repositories.ts b/packages/product/src/types/repositories.ts deleted file mode 100644 index 6f7f3a0510..0000000000 --- a/packages/product/src/types/repositories.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { DAL, ProductTypes, WithRequiredProperty } from "@medusajs/types" -import { - Image, - Product, - ProductCollection, - ProductOption, - ProductOptionValue, - ProductTag, - ProductType, - ProductVariant, -} from "@models" -import { UpdateProductDTO } from "./services/product" -import { - CreateProductCollection, - UpdateProductCollection, -} from "./services/product-collection" -import { - CreateProductOptionValueDTO, - UpdateProductOptionValueDTO, -} from "./services/product-option-value" -import { UpdateProductVariantDTO } from "./services/product-variant" - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IProductRepository - extends DAL.RepositoryService< - TEntity, - { - create: WithRequiredProperty - update: WithRequiredProperty - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IProductCollectionRepository< - TEntity extends ProductCollection = ProductCollection -> extends DAL.RepositoryService< - TEntity, - { - create: CreateProductCollection - update: UpdateProductCollection - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IProductImageRepository - extends DAL.RepositoryService {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IProductOptionRepository< - TEntity extends ProductOption = ProductOption -> extends DAL.RepositoryService< - TEntity, - { - create: ProductTypes.CreateProductOptionDTO - update: ProductTypes.UpdateProductOptionDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IProductOptionValueRepository< - TEntity extends ProductOptionValue = ProductOptionValue -> extends DAL.RepositoryService< - TEntity, - { - create: CreateProductOptionValueDTO - update: UpdateProductOptionValueDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IProductTagRepository - extends DAL.RepositoryService< - TEntity, - { - create: ProductTypes.CreateProductTagDTO - update: ProductTypes.UpdateProductTagDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IProductTypeRepository< - TEntity extends ProductType = ProductType -> extends DAL.RepositoryService< - TEntity, - { - create: ProductTypes.CreateProductTypeDTO - update: ProductTypes.UpdateProductTypeDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IProductVariantRepository< - TEntity extends ProductVariant = ProductVariant -> extends DAL.RepositoryService< - TEntity, - { - create: ProductTypes.CreateProductVariantOnlyDTO - update: UpdateProductVariantDTO - } - > {} diff --git a/packages/promotion/integration-tests/__tests__/services/promotion-module/campaign.spec.ts b/packages/promotion/integration-tests/__tests__/services/promotion-module/campaign.spec.ts index 122cde64af..a5d075f9fa 100644 --- a/packages/promotion/integration-tests/__tests__/services/promotion-module/campaign.spec.ts +++ b/packages/promotion/integration-tests/__tests__/services/promotion-module/campaign.spec.ts @@ -55,7 +55,7 @@ describe("Promotion Module Service: Campaigns", () => { campaign_identifier: "test-1", starts_at: expect.any(Date), ends_at: expect.any(Date), - budget: expect.any(String), + budget: expect.any(Object), created_at: expect.any(Date), updated_at: expect.any(Date), deleted_at: null, @@ -68,7 +68,7 @@ describe("Promotion Module Service: Campaigns", () => { campaign_identifier: "test-2", starts_at: expect.any(Date), ends_at: expect.any(Date), - budget: expect.any(String), + budget: expect.any(Object), created_at: expect.any(Date), updated_at: expect.any(Date), deleted_at: null, @@ -378,7 +378,7 @@ describe("Promotion Module Service: Campaigns", () => { error = e } - expect(error.message).toEqual('"campaignId" must be defined') + expect(error.message).toEqual("campaign - id must be defined") }) it("should return campaign based on config select param", async () => { diff --git a/packages/promotion/integration-tests/__tests__/services/promotion-module/promotion.spec.ts b/packages/promotion/integration-tests/__tests__/services/promotion-module/promotion.spec.ts index dc36e06613..94f6953370 100644 --- a/packages/promotion/integration-tests/__tests__/services/promotion-module/promotion.spec.ts +++ b/packages/promotion/integration-tests/__tests__/services/promotion-module/promotion.spec.ts @@ -890,7 +890,7 @@ describe("Promotion Service", () => { error = e } - expect(error.message).toEqual('"promotionId" must be defined') + expect(error.message).toEqual("promotion - id must be defined") }) it("should return promotion based on config select param", async () => { @@ -938,7 +938,7 @@ describe("Promotion Service", () => { campaign: null, is_automatic: false, type: "standard", - application_method: expect.any(String), + application_method: expect.any(Object), created_at: expect.any(Date), updated_at: expect.any(Date), deleted_at: null, @@ -1081,7 +1081,7 @@ describe("Promotion Service", () => { error = e } - expect(error.message).toEqual('"promotionId" must be defined') + expect(error.message).toEqual("promotion - id must be defined") }) it("should successfully create rules for a promotion", async () => { @@ -1156,7 +1156,7 @@ describe("Promotion Service", () => { error = e } - expect(error.message).toEqual('"promotionId" must be defined') + expect(error.message).toEqual("promotion - id must be defined") }) it("should successfully create target rules for a promotion", async () => { @@ -1246,7 +1246,7 @@ describe("Promotion Service", () => { error = e } - expect(error.message).toEqual('"promotionId" must be defined') + expect(error.message).toEqual("promotion - id must be defined") }) it("should successfully create buy rules for a buyget promotion", async () => { @@ -1334,7 +1334,7 @@ describe("Promotion Service", () => { error = e } - expect(error.message).toEqual('"promotionId" must be defined') + expect(error.message).toEqual("promotion - id must be defined") }) it("should successfully create rules for a promotion", async () => { @@ -1405,7 +1405,7 @@ describe("Promotion Service", () => { error = e } - expect(error.message).toEqual('"promotionId" must be defined') + expect(error.message).toEqual("promotion - id must be defined") }) it("should successfully create rules for a promotion", async () => { @@ -1489,7 +1489,7 @@ describe("Promotion Service", () => { error = e } - expect(error.message).toEqual('"promotionId" must be defined') + expect(error.message).toEqual("promotion - id must be defined") }) it("should successfully remove rules for a promotion", async () => { diff --git a/packages/promotion/src/repositories/campaign.ts b/packages/promotion/src/repositories/campaign.ts index 231dcb8563..afec080397 100644 --- a/packages/promotion/src/repositories/campaign.ts +++ b/packages/promotion/src/repositories/campaign.ts @@ -4,13 +4,9 @@ import { SqlEntityManager } from "@mikro-orm/postgresql" import { Campaign, Promotion } from "@models" import { CreateCampaignDTO, UpdateCampaignDTO } from "@types" -export class CampaignRepository extends DALUtils.mikroOrmBaseRepositoryFactory< - Campaign, - { - create: CreateCampaignDTO - update: UpdateCampaignDTO - } ->(Campaign) { +export class CampaignRepository extends DALUtils.mikroOrmBaseRepositoryFactory( + Campaign +) { async create( data: CreateCampaignDTO[], context: Context = {} @@ -64,7 +60,7 @@ export class CampaignRepository extends DALUtils.mikroOrmBaseRepositoryFactory< } async update( - data: UpdateCampaignDTO[], + data: { entity: Campaign; update: UpdateCampaignDTO }[], context: Context = {} ): Promise { const manager = this.getActiveManager(context) @@ -72,7 +68,7 @@ export class CampaignRepository extends DALUtils.mikroOrmBaseRepositoryFactory< const campaignIds: string[] = [] const campaignPromotionIdsMap = new Map() - data.forEach((campaignData) => { + data.forEach(({ update: campaignData }) => { const campaignPromotionIds = campaignData.promotions?.map((p) => p.id) campaignIds.push(campaignData.id) diff --git a/packages/promotion/src/services/application-method.ts b/packages/promotion/src/services/application-method.ts deleted file mode 100644 index 2f0e4d38be..0000000000 --- a/packages/promotion/src/services/application-method.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DAL, PromotionTypes } from "@medusajs/types" -import { ApplicationMethod } from "@models" -import { ModulesSdkUtils } from "@medusajs/utils" -import { CreateApplicationMethodDTO, UpdateApplicationMethodDTO } from "@types" - -type InjectedDependencies = { - applicationMethodRepository: DAL.RepositoryService -} - -export default class ApplicationMethodService< - TEntity extends ApplicationMethod = ApplicationMethod -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateApplicationMethodDTO - update: UpdateApplicationMethodDTO - }, - { - list: PromotionTypes.FilterableApplicationMethodProps - listAndCount: PromotionTypes.FilterableApplicationMethodProps - } ->(ApplicationMethod) { - constructor(...args: any[]) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/promotion/src/services/campaign-budget.ts b/packages/promotion/src/services/campaign-budget.ts deleted file mode 100644 index 269b337787..0000000000 --- a/packages/promotion/src/services/campaign-budget.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DAL, PromotionTypes } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { CampaignBudget } from "@models" -import { CreateCampaignBudgetDTO, UpdateCampaignBudgetDTO } from "../types" - -type InjectedDependencies = { - campaignBudgetRepository: DAL.RepositoryService -} - -export default class CampaignBudgetService< - TEntity extends CampaignBudget = CampaignBudget -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateCampaignBudgetDTO - update: UpdateCampaignBudgetDTO - }, - { - list: PromotionTypes.FilterableCampaignBudgetProps - listAndCount: PromotionTypes.FilterableCampaignBudgetProps - } ->(CampaignBudget) { - constructor(...args: any[]) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/promotion/src/services/campaign.ts b/packages/promotion/src/services/campaign.ts deleted file mode 100644 index 1f7b83adae..0000000000 --- a/packages/promotion/src/services/campaign.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DAL, PromotionTypes } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { Campaign } from "@models" -import { CreateCampaignDTO, UpdateCampaignDTO } from "../types" - -type InjectedDependencies = { - campaignRepository: DAL.RepositoryService -} - -export default class CampaignService< - TEntity extends Campaign = Campaign -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateCampaignDTO - update: UpdateCampaignDTO - }, - { - list: PromotionTypes.FilterableCampaignProps - listAndCount: PromotionTypes.FilterableCampaignProps - } ->(Campaign) { - constructor(...args: any[]) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/promotion/src/services/index.ts b/packages/promotion/src/services/index.ts index dcd93f46b8..c127ea20f4 100644 --- a/packages/promotion/src/services/index.ts +++ b/packages/promotion/src/services/index.ts @@ -1,7 +1 @@ -export { default as ApplicationMethodService } from "./application-method" -export { default as CampaignService } from "./campaign" -export { default as CampaignBudgetService } from "./campaign-budget" -export { default as PromotionService } from "./promotion" export { default as PromotionModuleService } from "./promotion-module" -export { default as PromotionRuleService } from "./promotion-rule" -export { default as PromotionRuleValueService } from "./promotion-rule-value" diff --git a/packages/promotion/src/services/promotion-module.ts b/packages/promotion/src/services/promotion-module.ts index 158e8201c6..2fc707942a 100644 --- a/packages/promotion/src/services/promotion-module.ts +++ b/packages/promotion/src/services/promotion-module.ts @@ -1,23 +1,21 @@ import { Context, DAL, - FindConfig, InternalModuleDeclaration, ModuleJoinerConfig, + ModulesSdkTypes, PromotionTypes, - RestoreReturn, - SoftDeleteReturn, } from "@medusajs/types" import { ApplicationMethodTargetType, CampaignBudgetType, InjectManager, InjectTransactionManager, + isString, MedusaContext, MedusaError, + ModulesSdkUtils, PromotionType, - isString, - mapObjectTo, } from "@medusajs/utils" import { ApplicationMethod, @@ -27,14 +25,6 @@ import { PromotionRule, PromotionRuleValue, } from "@models" -import { - ApplicationMethodService, - CampaignBudgetService, - CampaignService, - PromotionRuleService, - PromotionRuleValueService, - PromotionService, -} from "@services" import { ApplicationMethodRuleTypes, CreateApplicationMethodDTO, @@ -48,43 +38,60 @@ import { UpdatePromotionDTO, } from "@types" import { - ComputeActionUtils, allowedAllocationForQuantity, areRulesValidForContext, + ComputeActionUtils, validateApplicationMethodAttributes, validatePromotionRuleAttributes, } from "@utils" -import { - LinkableKeys, - entityNameToLinkableKeysMap, - joinerConfig, -} from "../joiner-config" +import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" type InjectedDependencies = { baseRepository: DAL.RepositoryService - promotionService: PromotionService - applicationMethodService: ApplicationMethodService - promotionRuleService: PromotionRuleService - promotionRuleValueService: PromotionRuleValueService - campaignService: CampaignService - campaignBudgetService: CampaignBudgetService + promotionService: ModulesSdkTypes.InternalModuleService + applicationMethodService: ModulesSdkTypes.InternalModuleService + promotionRuleService: ModulesSdkTypes.InternalModuleService + promotionRuleValueService: ModulesSdkTypes.InternalModuleService + campaignService: ModulesSdkTypes.InternalModuleService + campaignBudgetService: ModulesSdkTypes.InternalModuleService } +const generateMethodForModels = [ + ApplicationMethod, + Campaign, + CampaignBudget, + PromotionRule, + PromotionRuleValue, +] + export default class PromotionModuleService< - TPromotion extends Promotion = Promotion, - TPromotionRule extends PromotionRule = PromotionRule, - TPromotionRuleValue extends PromotionRuleValue = PromotionRuleValue, - TCampaign extends Campaign = Campaign, - TCampaignBudget extends CampaignBudget = CampaignBudget -> implements PromotionTypes.IPromotionModuleService + TApplicationMethod extends ApplicationMethod = ApplicationMethod, + TPromotion extends Promotion = Promotion, + TPromotionRule extends PromotionRule = PromotionRule, + TPromotionRuleValue extends PromotionRuleValue = PromotionRuleValue, + TCampaign extends Campaign = Campaign, + TCampaignBudget extends CampaignBudget = CampaignBudget + > + extends ModulesSdkUtils.abstractModuleServiceFactory< + InjectedDependencies, + PromotionTypes.PromotionDTO, + { + ApplicationMethod: { dto: PromotionTypes.ApplicationMethodDTO } + Campaign: { dto: PromotionTypes.CampaignDTO } + CampaignBudget: { dto: PromotionTypes.CampaignBudgetDTO } + PromotionRule: { dto: PromotionTypes.PromotionRuleDTO } + PromotionRuleValue: { dto: PromotionTypes.PromotionRuleValueDTO } + } + >(Promotion, generateMethodForModels, entityNameToLinkableKeysMap) + implements PromotionTypes.IPromotionModuleService { protected baseRepository_: DAL.RepositoryService - protected promotionService_: PromotionService - protected applicationMethodService_: ApplicationMethodService - protected promotionRuleService_: PromotionRuleService - protected promotionRuleValueService_: PromotionRuleValueService - protected campaignService_: CampaignService - protected campaignBudgetService_: CampaignBudgetService + protected promotionService_: ModulesSdkTypes.InternalModuleService + protected applicationMethodService_: ModulesSdkTypes.InternalModuleService + protected promotionRuleService_: ModulesSdkTypes.InternalModuleService + protected promotionRuleValueService_: ModulesSdkTypes.InternalModuleService + protected campaignService_: ModulesSdkTypes.InternalModuleService + protected campaignBudgetService_: ModulesSdkTypes.InternalModuleService constructor( { @@ -98,6 +105,9 @@ export default class PromotionModuleService< }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { + // @ts-ignore + super(...arguments) + this.baseRepository_ = baseRepository this.promotionService_ = promotionService this.applicationMethodService_ = applicationMethodService @@ -399,63 +409,6 @@ export default class PromotionModuleService< return computedActions } - @InjectManager("baseRepository_") - async retrieve( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const promotion = await this.promotionService_.retrieve( - id, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - promotion, - { populate: true } - ) - } - - @InjectManager("baseRepository_") - async list( - filters: PromotionTypes.FilterablePromotionProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const promotions = await this.promotionService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - promotions, - { populate: true } - ) - } - - @InjectManager("baseRepository_") - async listAndCount( - filters: PromotionTypes.FilterablePromotionProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PromotionTypes.PromotionDTO[], number]> { - const [promotions, count] = await this.promotionService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - promotions, - { populate: true } - ), - count, - ] - } - async create( data: PromotionTypes.CreatePromotionDTO, sharedContext?: Context @@ -921,88 +874,6 @@ export default class PromotionModuleService< } } - @InjectTransactionManager("baseRepository_") - async delete( - ids: string[] | string, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const idsToDelete = Array.isArray(ids) ? ids : [ids] - - await this.promotionService_.delete(idsToDelete, sharedContext) - } - - @InjectManager("baseRepository_") - async softDelete< - TReturnableLinkableKeys extends string = Lowercase< - keyof typeof LinkableKeys - > - >( - ids: string | string[], - { returnLinkableKeys }: SoftDeleteReturn = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise, string[]> | void> { - const idsToDelete = Array.isArray(ids) ? ids : [ids] - let [_, cascadedEntitiesMap] = await this.softDelete_( - idsToDelete, - sharedContext - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - - @InjectTransactionManager("baseRepository_") - protected async softDelete_( - promotionIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise<[TPromotion[], Record]> { - return await this.promotionService_.softDelete(promotionIds, sharedContext) - } - - @InjectManager("baseRepository_") - async restore< - TReturnableLinkableKeys extends string = Lowercase< - keyof typeof LinkableKeys - > - >( - ids: string | string[], - { returnLinkableKeys }: RestoreReturn = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise, string[]> | void> { - const idsToRestore = Array.isArray(ids) ? ids : [ids] - const [_, cascadedEntitiesMap] = await this.restore_( - idsToRestore, - sharedContext - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - - @InjectTransactionManager("baseRepository_") - async restore_( - ids: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise<[TPromotion[], Record]> { - return await this.promotionService_.restore(ids, sharedContext) - } - @InjectManager("baseRepository_") async removePromotionRules( promotionId: string, @@ -1134,63 +1005,6 @@ export default class PromotionModuleService< ) } - @InjectManager("baseRepository_") - async retrieveCampaign( - id: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const campaign = await this.campaignService_.retrieve( - id, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - campaign, - { populate: true } - ) - } - - @InjectManager("baseRepository_") - async listCampaigns( - filters: PromotionTypes.FilterableCampaignProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const campaigns = await this.campaignService_.list( - filters, - config, - sharedContext - ) - - return await this.baseRepository_.serialize( - campaigns, - { populate: true } - ) - } - - @InjectManager("baseRepository_") - async listAndCountCampaigns( - filters: PromotionTypes.FilterableCampaignProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[PromotionTypes.CampaignDTO[], number]> { - const [campaigns, count] = await this.campaignService_.listAndCount( - filters, - config, - sharedContext - ) - - return [ - await this.baseRepository_.serialize( - campaigns, - { populate: true } - ), - count, - ] - } - async createCampaigns( data: PromotionTypes.CreateCampaignDTO, sharedContext?: Context @@ -1361,82 +1175,4 @@ export default class PromotionModuleService< return updatedCampaigns } - - @InjectTransactionManager("baseRepository_") - async deleteCampaigns( - ids: string | string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - const idsToDelete = Array.isArray(ids) ? ids : [ids] - - await this.campaignService_.delete(idsToDelete, sharedContext) - } - - @InjectManager("baseRepository_") - async softDeleteCampaigns( - ids: string | string[], - { returnLinkableKeys }: SoftDeleteReturn = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise, string[]> | void> { - const idsToDelete = Array.isArray(ids) ? ids : [ids] - let [_, cascadedEntitiesMap] = await this.softDeleteCampaigns_( - idsToDelete, - sharedContext - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - - @InjectTransactionManager("baseRepository_") - protected async softDeleteCampaigns_( - campaignIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise<[TCampaign[], Record]> { - return await this.campaignService_.softDelete(campaignIds, sharedContext) - } - - @InjectManager("baseRepository_") - async restoreCampaigns< - TReturnableLinkableKeys extends string = Lowercase< - keyof typeof LinkableKeys - > - >( - ids: string | string[], - { returnLinkableKeys }: RestoreReturn = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise, string[]> | void> { - const idsToRestore = Array.isArray(ids) ? ids : [ids] - const [_, cascadedEntitiesMap] = await this.restoreCampaigns_( - idsToRestore, - sharedContext - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - - @InjectTransactionManager("baseRepository_") - async restoreCampaigns_( - ids: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise<[TCampaign[], Record]> { - return await this.campaignService_.restore(ids, sharedContext) - } } diff --git a/packages/promotion/src/services/promotion-rule-value.ts b/packages/promotion/src/services/promotion-rule-value.ts deleted file mode 100644 index 90a0487d94..0000000000 --- a/packages/promotion/src/services/promotion-rule-value.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { DAL, PromotionTypes } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { PromotionRuleValue } from "@models" -import { - CreatePromotionRuleValueDTO, - UpdatePromotionRuleValueDTO, -} from "../types" - -type InjectedDependencies = { - promotionRuleValueRepository: DAL.RepositoryService -} - -export default class PromotionRuleValueService< - TEntity extends PromotionRuleValue = PromotionRuleValue -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreatePromotionRuleValueDTO - update: UpdatePromotionRuleValueDTO - }, - { - list: PromotionTypes.FilterablePromotionRuleValueProps - listAndCount: PromotionTypes.FilterablePromotionRuleValueProps - } ->(PromotionRuleValue) { - constructor(...args: any[]) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/promotion/src/services/promotion-rule.ts b/packages/promotion/src/services/promotion-rule.ts deleted file mode 100644 index a8654617c7..0000000000 --- a/packages/promotion/src/services/promotion-rule.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DAL, PromotionTypes } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { PromotionRule } from "@models" -import { CreatePromotionRuleDTO, UpdatePromotionRuleDTO } from "../types" - -type InjectedDependencies = { - promotionRuleRepository: DAL.RepositoryService -} - -export default class PromotionRuleService< - TEntity extends PromotionRule = PromotionRule -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreatePromotionRuleDTO - update: UpdatePromotionRuleDTO - }, - { - list: PromotionTypes.FilterablePromotionRuleProps - listAndCount: PromotionTypes.FilterablePromotionRuleProps - } ->(PromotionRule) { - constructor(...args: any[]) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/promotion/src/services/promotion.ts b/packages/promotion/src/services/promotion.ts deleted file mode 100644 index 74c8e71ba3..0000000000 --- a/packages/promotion/src/services/promotion.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DAL, PromotionTypes } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { Promotion } from "@models" -import { CreatePromotionDTO, UpdatePromotionDTO } from "../types" - -type InjectedDependencies = { - promotionRepository: DAL.RepositoryService -} - -export default class PromotionService< - TEntity extends Promotion = Promotion -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreatePromotionDTO - update: UpdatePromotionDTO - }, - { - list: PromotionTypes.FilterablePromotionProps - listAndCount: PromotionTypes.FilterablePromotionProps - } ->(Promotion) { - constructor(...args: any[]) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/promotion/src/types/index.ts b/packages/promotion/src/types/index.ts index 80891678e3..145c717bae 100644 --- a/packages/promotion/src/types/index.ts +++ b/packages/promotion/src/types/index.ts @@ -10,4 +10,3 @@ export * from "./campaign-budget" export * from "./promotion" export * from "./promotion-rule" export * from "./promotion-rule-value" -export * from "./repositories" diff --git a/packages/promotion/src/types/repositories.ts b/packages/promotion/src/types/repositories.ts deleted file mode 100644 index bfa06a3073..0000000000 --- a/packages/promotion/src/types/repositories.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { - ApplicationMethod, - Campaign, - CampaignBudget, - Promotion, - PromotionRule, - PromotionRuleValue, -} from "@models" -import { DAL } from "@medusajs/types" -import { - CreateApplicationMethodDTO, - UpdateApplicationMethodDTO, -} from "./application-method" -import { CreateCampaignDTO, UpdateCampaignDTO } from "./campaign" -import { - CreateCampaignBudgetDTO, - UpdateCampaignBudgetDTO, -} from "./campaign-budget" -import { CreatePromotionDTO, UpdatePromotionDTO } from "./promotion" -import { - CreatePromotionRuleDTO, - UpdatePromotionRuleDTO, -} from "./promotion-rule" -import { - CreatePromotionRuleValueDTO, - UpdatePromotionRuleValueDTO, -} from "./promotion-rule-value" - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IApplicationMethodRepository< - TEntity extends ApplicationMethod = ApplicationMethod -> extends DAL.RepositoryService< - TEntity, - { - create: CreateApplicationMethodDTO - update: UpdateApplicationMethodDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ICampaignRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreateCampaignDTO - update: UpdateCampaignDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ICampaignBudgetRepository< - TEntity extends CampaignBudget = CampaignBudget -> extends DAL.RepositoryService< - TEntity, - { - create: CreateCampaignBudgetDTO - update: UpdateCampaignBudgetDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPromotionRepository - extends DAL.RepositoryService< - TEntity, - { - create: CreatePromotionDTO - Update: UpdatePromotionDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPromotionRuleRepository< - TEntity extends PromotionRule = PromotionRule -> extends DAL.RepositoryService< - TEntity, - { - create: CreatePromotionRuleDTO - update: UpdatePromotionRuleDTO - } - > {} - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface IPromotionRuleValueRepository< - TEntity extends PromotionRuleValue = PromotionRuleValue -> extends DAL.RepositoryService< - TEntity, - { - create: CreatePromotionRuleValueDTO - update: UpdatePromotionRuleValueDTO - } - > {} diff --git a/packages/sales-channel/src/services/__fixtures__/sales-channel.ts b/packages/sales-channel/src/services/__fixtures__/sales-channel.ts index c4a716dde4..4549d004b4 100644 --- a/packages/sales-channel/src/services/__fixtures__/sales-channel.ts +++ b/packages/sales-channel/src/services/__fixtures__/sales-channel.ts @@ -1,10 +1,6 @@ -import { SalesChannelService, SalesChannelModuleService } from "@services" -import { asClass, asValue, createContainer } from "awilix" +import { asValue } from "awilix" -export const mockContainer = createContainer() - -mockContainer.register({ - transaction: asValue(async (task) => await task()), +export const salesChannelRepositoryMock = { salesChannelRepository: asValue({ find: jest.fn().mockImplementation(async ({ where: { code } }) => { return [{}] @@ -12,6 +8,4 @@ mockContainer.register({ findAndCount: jest.fn().mockResolvedValue([[], 0]), getFreshManager: jest.fn().mockResolvedValue({}), }), - salesChannelService: asClass(SalesChannelService), - salesChannelModuleService: asClass(SalesChannelModuleService), -}) +} diff --git a/packages/sales-channel/src/services/__tests__/sales-channle.spec.ts b/packages/sales-channel/src/services/__tests__/sales-channle.spec.ts index d8dab120bd..61e5bb1a1f 100644 --- a/packages/sales-channel/src/services/__tests__/sales-channle.spec.ts +++ b/packages/sales-channel/src/services/__tests__/sales-channle.spec.ts @@ -1,15 +1,25 @@ -import { mockContainer } from "../__fixtures__/sales-channel" +import { createMedusaContainer } from "@medusajs/utils" +import { asValue } from "awilix" +import ContainerLoader from "../../loaders/container" +import { salesChannelRepositoryMock } from "../__fixtures__/sales-channel" describe("Sales channel service", function () { - beforeEach(function () { + let container + + beforeEach(async function () { jest.clearAllMocks() + + container = createMedusaContainer() + container.register("manager", asValue({})) + + await ContainerLoader({ container }) + + container.register(salesChannelRepositoryMock) }) it("should list sales channels with filters and relations", async function () { - const salesChannelRepository = mockContainer.resolve( - "salesChannelRepository" - ) - const salesChannelService = mockContainer.resolve("salesChannelService") + const salesChannelRepository = container.resolve("salesChannelRepository") + const salesChannelService = container.resolve("salesChannelService") const config = { select: ["id", "name"], diff --git a/packages/sales-channel/src/services/index.ts b/packages/sales-channel/src/services/index.ts index 117f8a36c6..d00ec9ecfc 100644 --- a/packages/sales-channel/src/services/index.ts +++ b/packages/sales-channel/src/services/index.ts @@ -1,2 +1 @@ -export { default as SalesChannelService } from "./sales-channel" export { default as SalesChannelModuleService } from "./sales-channel-module" diff --git a/packages/sales-channel/src/services/sales-channel-module.ts b/packages/sales-channel/src/services/sales-channel-module.ts index 270629f7c6..b9d02de4ea 100644 --- a/packages/sales-channel/src/services/sales-channel-module.ts +++ b/packages/sales-channel/src/services/sales-channel-module.ts @@ -1,48 +1,48 @@ import { Context, + CreateSalesChannelDTO, DAL, - FilterableSalesChannelProps, - FindConfig, InternalModuleDeclaration, ISalesChannelModuleService, ModuleJoinerConfig, - RestoreReturn, + ModulesSdkTypes, SalesChannelDTO, - SoftDeleteReturn, + UpdateSalesChannelDTO, } from "@medusajs/types" import { - InjectManager, InjectTransactionManager, - mapObjectTo, MedusaContext, + ModulesSdkUtils, } from "@medusajs/utils" -import { CreateSalesChannelDTO, UpdateSalesChannelDTO } from "@medusajs/types" import { SalesChannel } from "@models" -import SalesChannelService from "./sales-channel" -import { - joinerConfig, - entityNameToLinkableKeysMap, - LinkableKeys, -} from "../joiner-config" +import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" type InjectedDependencies = { baseRepository: DAL.RepositoryService - salesChannelService: SalesChannelService + salesChannelService: ModulesSdkTypes.InternalModuleService } export default class SalesChannelModuleService< - TEntity extends SalesChannel = SalesChannel -> implements ISalesChannelModuleService + TEntity extends SalesChannel = SalesChannel + > + extends ModulesSdkUtils.abstractModuleServiceFactory< + InjectedDependencies, + SalesChannelDTO, + {} + >(SalesChannel, [], entityNameToLinkableKeysMap) + implements ISalesChannelModuleService { protected baseRepository_: DAL.RepositoryService - protected readonly salesChannelService_: SalesChannelService + protected readonly salesChannelService_: ModulesSdkTypes.InternalModuleService constructor( { baseRepository, salesChannelService }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { + // @ts-ignore + super(...arguments) this.baseRepository_ = baseRepository this.salesChannelService_ = salesChannelService } @@ -78,95 +78,6 @@ export default class SalesChannelModuleService< ) } - async delete(ids: string[], sharedContext?: Context): Promise - - async delete(id: string, sharedContext?: Context): Promise - - @InjectTransactionManager("baseRepository_") - async delete( - ids: string | string[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - const salesChannelIds = Array.isArray(ids) ? ids : [ids] - await this.salesChannelService_.delete(salesChannelIds, sharedContext) - } - - @InjectTransactionManager("baseRepository_") - protected async softDelete_( - salesChannelIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise<[TEntity[], Record]> { - return await this.salesChannelService_.softDelete( - salesChannelIds, - sharedContext - ) - } - - @InjectManager("baseRepository_") - async softDelete< - TReturnableLinkableKeys extends string = Lowercase< - keyof typeof LinkableKeys - > - >( - salesChannelIds: string[], - { returnLinkableKeys }: SoftDeleteReturn = {}, - sharedContext: Context = {} - ): Promise, string[]> | void> { - const [_, cascadedEntitiesMap] = await this.softDelete_( - salesChannelIds, - sharedContext - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - - @InjectTransactionManager("baseRepository_") - async restore_( - salesChannelIds: string[], - @MedusaContext() sharedContext: Context = {} - ): Promise<[TEntity[], Record]> { - return await this.salesChannelService_.restore( - salesChannelIds, - sharedContext - ) - } - - @InjectManager("baseRepository_") - async restore< - TReturnableLinkableKeys extends string = Lowercase< - keyof typeof LinkableKeys - > - >( - salesChannelIds: string[], - { returnLinkableKeys }: RestoreReturn = {}, - sharedContext: Context = {} - ): Promise, string[]> | void> { - const [_, cascadedEntitiesMap] = await this.restore_( - salesChannelIds, - sharedContext - ) - - let mappedCascadedEntitiesMap - if (returnLinkableKeys) { - mappedCascadedEntitiesMap = mapObjectTo< - Record, string[]> - >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { - pick: returnLinkableKeys, - }) - } - - return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 - } - async update( data: UpdateSalesChannelDTO[], sharedContext?: Context @@ -193,55 +104,4 @@ export default class SalesChannelModuleService< } ) } - - @InjectManager("baseRepository_") - async retrieve( - salesChannelId: string, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const salesChannel = await this.salesChannelService_.retrieve( - salesChannelId, - config - ) - - return await this.baseRepository_.serialize(salesChannel, { - populate: true, - }) - } - - @InjectManager("baseRepository_") - async list( - filters: {} = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const salesChannels = await this.salesChannelService_.list(filters, config) - - return await this.baseRepository_.serialize( - salesChannels, - { - populate: true, - } - ) - } - - @InjectManager("baseRepository_") - async listAndCount( - filters: FilterableSalesChannelProps = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[SalesChannelDTO[], number]> { - const [salesChannels, count] = await this.salesChannelService_.listAndCount( - filters, - config - ) - - return [ - await this.baseRepository_.serialize(salesChannels, { - populate: true, - }), - count, - ] - } } diff --git a/packages/sales-channel/src/services/sales-channel.ts b/packages/sales-channel/src/services/sales-channel.ts deleted file mode 100644 index 83e6ef90b4..0000000000 --- a/packages/sales-channel/src/services/sales-channel.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { CreateSalesChannelDTO, UpdateSalesChannelDTO } from "@medusajs/types" - -import { SalesChannel } from "@models" - -type InjectedDependencies = { - salesChannelRepository: DAL.RepositoryService -} - -export default class SalesChannelService< - TEntity extends SalesChannel = SalesChannel -> extends ModulesSdkUtils.abstractServiceFactory< - InjectedDependencies, - { - create: CreateSalesChannelDTO - update: UpdateSalesChannelDTO - } ->(SalesChannel) { - constructor(container: InjectedDependencies) { - // @ts-ignore - super(...arguments) - } -} diff --git a/packages/sales-channel/src/types/repositories.ts b/packages/sales-channel/src/types/repositories.ts deleted file mode 100644 index e1a90fef21..0000000000 --- a/packages/sales-channel/src/types/repositories.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { DAL } from "@medusajs/types" - -// eslint-disable-next-line @typescript-eslint/no-empty-interface -import { SalesChannel } from "@models" -import { CreateSalesChannelDTO, UpdateSalesChannelDTO } from "@medusajs/types" - -export interface ISalesChannelRepository< - TEntity extends SalesChannel = SalesChannel -> extends DAL.RepositoryService< - TEntity, - { - create: CreateSalesChannelDTO - update: UpdateSalesChannelDTO - } - > {} diff --git a/packages/types/src/auth/common/auth-provider.ts b/packages/types/src/auth/common/auth-provider.ts index 3f4122d42f..ddf8338797 100644 --- a/packages/types/src/auth/common/auth-provider.ts +++ b/packages/types/src/auth/common/auth-provider.ts @@ -25,6 +25,7 @@ export type UpdateAuthProviderDTO = { export interface FilterableAuthProviderProps extends BaseFilterable { + id?: string | string[] provider?: string[] is_active?: boolean scope?: string[] diff --git a/packages/types/src/auth/service.ts b/packages/types/src/auth/service.ts index 88b72362db..1dd4c4ecc2 100644 --- a/packages/types/src/auth/service.ts +++ b/packages/types/src/auth/service.ts @@ -68,7 +68,7 @@ export interface IAuthModuleService extends IModuleService { sharedContext?: Context ): Promise - deleteAuthProvider(ids: string[], sharedContext?: Context): Promise + deleteAuthProviders(ids: string[], sharedContext?: Context): Promise retrieveAuthUser( id: string, @@ -118,5 +118,5 @@ export interface IAuthModuleService extends IModuleService { sharedContext?: Context ): Promise - deleteAuthUser(ids: string[], sharedContext?: Context): Promise + deleteAuthUsers(ids: string[], sharedContext?: Context): Promise } diff --git a/packages/types/src/common/common.ts b/packages/types/src/common/common.ts index 99c3dd9367..d97ebd31fb 100644 --- a/packages/types/src/common/common.ts +++ b/packages/types/src/common/common.ts @@ -4,11 +4,11 @@ import { FindOperator, FindOptionsSelect, FindOptionsWhere, - OrderByCondition -} from "typeorm"; + OrderByCondition, +} from "typeorm" -import { FindOptionsOrder } from "typeorm/find-options/FindOptionsOrder"; -import { FindOptionsRelations } from "typeorm/find-options/FindOptionsRelations"; +import { FindOptionsOrder } from "typeorm/find-options/FindOptionsOrder" +import { FindOptionsRelations } from "typeorm/find-options/FindOptionsRelations" /** * Utility type used to remove some optional attributes (coming from K) from a type T @@ -230,3 +230,17 @@ export interface FindPaginationParams { offset?: number limit?: number } + +export type Pluralize = Singular extends `${infer R}y` + ? `${R}ies` + : Singular extends `${infer R}es` + ? `${Singular}` + : Singular extends + | `${infer R}ss` + | `${infer R}sh` + | `${infer R}ch` + | `${infer R}x` + | `${infer R}z` + | `${infer R}o` + ? `${Singular}es` + : `${Singular}s` diff --git a/packages/types/src/customer/service.ts b/packages/types/src/customer/service.ts index 8143bd213a..b2c348ffe0 100644 --- a/packages/types/src/customer/service.ts +++ b/packages/types/src/customer/service.ts @@ -3,15 +3,15 @@ import { RestoreReturn, SoftDeleteReturn } from "../dal" import { IModuleService } from "../modules-sdk" import { Context } from "../shared-context" import { - CustomerDTO, - CustomerGroupDTO, - CustomerGroupCustomerDTO, - FilterableCustomerGroupCustomerProps, - FilterableCustomerProps, - FilterableCustomerGroupProps, - GroupCustomerPair, - FilterableCustomerAddressProps, CustomerAddressDTO, + CustomerDTO, + CustomerGroupCustomerDTO, + CustomerGroupDTO, + FilterableCustomerAddressProps, + FilterableCustomerGroupCustomerProps, + FilterableCustomerGroupProps, + FilterableCustomerProps, + GroupCustomerPair, } from "./common" import { CreateCustomerAddressDTO, @@ -58,11 +58,13 @@ export interface ICustomerModuleService extends IModuleService { sharedContext?: Context ): Promise + // TODO should be pluralized createCustomerGroup( data: CreateCustomerGroupDTO[], sharedContext?: Context ): Promise + // TODO should be pluralized createCustomerGroup( data: CreateCustomerGroupDTO, sharedContext?: Context @@ -74,28 +76,30 @@ export interface ICustomerModuleService extends IModuleService { sharedContext?: Context ): Promise - updateCustomerGroup( + updateCustomerGroups( groupId: string, data: CustomerGroupUpdatableFields, sharedContext?: Context ): Promise - updateCustomerGroup( + + updateCustomerGroups( groupIds: string[], data: CustomerGroupUpdatableFields, sharedContext?: Context ): Promise - updateCustomerGroup( + + updateCustomerGroups( selector: FilterableCustomerGroupProps, data: CustomerGroupUpdatableFields, sharedContext?: Context ): Promise - deleteCustomerGroup(groupId: string, sharedContext?: Context): Promise - deleteCustomerGroup( + deleteCustomerGroups(groupId: string, sharedContext?: Context): Promise + deleteCustomerGroups( groupIds: string[], sharedContext?: Context ): Promise - deleteCustomerGroup( + deleteCustomerGroups( selector: FilterableCustomerGroupProps, sharedContext?: Context ): Promise @@ -110,10 +114,13 @@ export interface ICustomerModuleService extends IModuleService { sharedContext?: Context ): Promise<{ id: string }[]> + // TODO should be pluralized removeCustomerFromGroup( groupCustomerPair: GroupCustomerPair, sharedContext?: Context ): Promise + + // TODO should be pluralized removeCustomerFromGroup( groupCustomerPairs: GroupCustomerPair[], sharedContext?: Context @@ -128,25 +135,26 @@ export interface ICustomerModuleService extends IModuleService { sharedContext?: Context ): Promise - updateAddress( + updateAddresses( addressId: string, data: UpdateCustomerAddressDTO, sharedContext?: Context ): Promise - updateAddress( + updateAddresses( addressIds: string[], data: UpdateCustomerAddressDTO, sharedContext?: Context ): Promise - updateAddress( + + updateAddresses( selector: FilterableCustomerAddressProps, data: UpdateCustomerAddressDTO, sharedContext?: Context ): Promise - deleteAddress(addressId: string, sharedContext?: Context): Promise - deleteAddress(addressIds: string[], sharedContext?: Context): Promise - deleteAddress( + deleteAddresses(addressId: string, sharedContext?: Context): Promise + deleteAddresses(addressIds: string[], sharedContext?: Context): Promise + deleteAddresses( selector: FilterableCustomerAddressProps, sharedContext?: Context ): Promise @@ -163,7 +171,7 @@ export interface ICustomerModuleService extends IModuleService { sharedContext?: Context ): Promise<[CustomerAddressDTO[], number]> - listCustomerGroupRelations( + listCustomerGroupCustomers( filters?: FilterableCustomerGroupCustomerProps, config?: FindConfig, sharedContext?: Context @@ -205,13 +213,13 @@ export interface ICustomerModuleService extends IModuleService { sharedContext?: Context ): Promise | void> - softDeleteCustomerGroup( + softDeleteCustomerGroups( groupIds: string[], config?: SoftDeleteReturn, sharedContext?: Context ): Promise | void> - restoreCustomerGroup( + restoreCustomerGroups( groupIds: string[], config?: RestoreReturn, sharedContext?: Context diff --git a/packages/types/src/dal/repository-service.ts b/packages/types/src/dal/repository-service.ts index cc18daff1a..a2f5339e8b 100644 --- a/packages/types/src/dal/repository-service.ts +++ b/packages/types/src/dal/repository-service.ts @@ -1,6 +1,11 @@ import { RepositoryTransformOptions } from "../common" import { Context } from "../shared-context" -import { FindOptions } from "./index" +import { + BaseFilterable, + FilterQuery as InternalFilterQuery, + FilterQuery, + FindOptions, +} from "./index" /** * Data access layer (DAL) interface to implements for any repository service. @@ -29,12 +34,7 @@ interface BaseRepositoryService { type DtoBasedMutationMethods = "create" | "update" -export interface RepositoryService< - T = any, - TDTOs extends { [K in DtoBasedMutationMethods]?: any } = { - [K in DtoBasedMutationMethods]?: any - } -> extends BaseRepositoryService { +export interface RepositoryService extends BaseRepositoryService { find(options?: FindOptions, context?: Context): Promise findAndCount( @@ -42,34 +42,34 @@ export interface RepositoryService< context?: Context ): Promise<[T[], number]> - create(data: TDTOs["create"][], context?: Context): Promise + create(data: any[], context?: Context): Promise - update(data: TDTOs["update"][], context?: Context): Promise + update(data: { entity; update }[], context?: Context): Promise - delete(idsOrPKs: string[] | object[], context?: Context): Promise + delete( + idsOrPKs: FilterQuery & BaseFilterable>, + context?: Context + ): Promise /** * Soft delete entities and cascade to related entities if configured. * - * @param ids + * @param idsOrFilter * @param context * * @returns [T[], Record] the second value being the map of the entity names and ids that were soft deleted */ softDelete( - ids: string[], + idsOrFilter: string[] | InternalFilterQuery, context?: Context ): Promise<[T[], Record]> restore( - ids: string[], + idsOrFilter: string[] | InternalFilterQuery, context?: Context ): Promise<[T[], Record]> - upsert( - data: (TDTOs["create"] | TDTOs["update"])[], - context?: Context - ): Promise + upsert(data: any[], context?: Context): Promise } export interface TreeRepositoryService diff --git a/packages/types/src/modules-sdk/index.ts b/packages/types/src/modules-sdk/index.ts index c69a3e90a1..8780aa80ec 100644 --- a/packages/types/src/modules-sdk/index.ts +++ b/packages/types/src/modules-sdk/index.ts @@ -10,6 +10,7 @@ import { Logger } from "../logger" export type Constructor = new (...args: any[]) => T export * from "../common/medusa-container" +export * from "./internal-module-service" export type LogLevel = | "query" diff --git a/packages/types/src/modules-sdk/internal-module-service.ts b/packages/types/src/modules-sdk/internal-module-service.ts new file mode 100644 index 0000000000..10c1622511 --- /dev/null +++ b/packages/types/src/modules-sdk/internal-module-service.ts @@ -0,0 +1,81 @@ +import { FindConfig } from "../common" +import { Context } from "../shared-context" +import { + BaseFilterable, + FilterQuery as InternalFilterQuery, + FilterQuery, +} from "../dal" + +export interface InternalModuleService< + TEntity extends {}, + TContainer extends object = object +> { + get __container__(): TContainer + + retrieve( + idOrObject: string, + config?: FindConfig, + sharedContext?: Context + ): Promise + retrieve( + idOrObject: object, + config?: FindConfig, + sharedContext?: Context + ): Promise + + list( + filters?: FilterQuery | BaseFilterable>, + config?: FindConfig, + sharedContext?: Context + ): Promise + + listAndCount( + filters?: FilterQuery | BaseFilterable>, + config?: FindConfig, + sharedContext?: Context + ): Promise<[TEntity[], number]> + + create(data: any[], sharedContext?: Context): Promise + create(data: any, sharedContext?: Context): Promise + + update(data: any[], sharedContext?: Context): Promise + update(data: any, sharedContext?: Context): Promise + update( + selectorAndData: { + selector: FilterQuery | BaseFilterable> + data: any + }, + sharedContext?: Context + ): Promise + update( + selectorAndData: { + selector: FilterQuery | BaseFilterable> + data: any + }[], + sharedContext?: Context + ): Promise + + delete(idOrSelector: string, sharedContext?: Context): Promise + delete(idOrSelector: string[], sharedContext?: Context): Promise + delete(idOrSelector: object, sharedContext?: Context): Promise + delete(idOrSelector: object[], sharedContext?: Context): Promise + delete( + idOrSelector: { + selector: FilterQuery | BaseFilterable> + }, + sharedContext?: Context + ): Promise + + softDelete( + idsOrFilter: string[] | InternalFilterQuery, + sharedContext?: Context + ): Promise<[TEntity[], Record]> + + restore( + idsOrFilter: string[] | InternalFilterQuery, + sharedContext?: Context + ): Promise<[TEntity[], Record]> + + upsert(data: any[], sharedContext?: Context): Promise + upsert(data: any, sharedContext?: Context): Promise +} diff --git a/packages/types/src/modules-sdk/module-service.ts b/packages/types/src/modules-sdk/module-service.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/types/src/payment/service.ts b/packages/types/src/payment/service.ts index 94951f5545..ed5c12d601 100644 --- a/packages/types/src/payment/service.ts +++ b/packages/types/src/payment/service.ts @@ -54,11 +54,11 @@ export interface IPaymentModuleService extends IModuleService { sharedContext?: Context ): Promise - deletePaymentCollection( + deletePaymentCollections( paymentCollectionId: string[], sharedContext?: Context ): Promise - deletePaymentCollection( + deletePaymentCollections( paymentCollectionId: string, sharedContext?: Context ): Promise diff --git a/packages/types/src/pricing/service.ts b/packages/types/src/pricing/service.ts index bf433aaa89..0a88f48e95 100644 --- a/packages/types/src/pricing/service.ts +++ b/packages/types/src/pricing/service.ts @@ -47,7 +47,7 @@ import { import { FindConfig } from "../common" import { ModuleJoinerConfig } from "../modules-sdk" import { Context } from "../shared-context" -import { RestoreReturn } from "../dal" +import { RestoreReturn, SoftDeleteReturn } from "../dal" export interface IPricingModuleService { /** @@ -1279,6 +1279,7 @@ export interface IPricingModuleService { * This method soft deletes money amounts by their IDs. * * @param {string[]} ids - The IDs of the money amounts to delete. + * @param {SoftDeleteReturn} config * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. * @returns {Promise} Resolves when the money amounts are successfully deleted. * @@ -1295,7 +1296,11 @@ export interface IPricingModuleService { * ) * } */ - softDeleteMoneyAmounts(ids: string[], sharedContext?: Context): Promise + softDeleteMoneyAmounts( + ids: string[], + config?: SoftDeleteReturn, + sharedContext?: Context + ): Promise | void> /** * This method restores soft deleted money amounts by their IDs. @@ -1305,10 +1310,10 @@ export interface IPricingModuleService { * Configurations determining which relations to restore along with each of the money amounts. You can pass to its `returnLinkableKeys` * property any of the money amount's relation attribute names, such as `price_set_money_amount`. * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. - * @returns {Promise | void>} - * An object that includes the IDs of related records that were restored, such as the ID of associated price set money amounts. - * The object's keys are the ID attribute names of the money amount entity's relations, such as `price_set_money_amount_id`, - * and its value is an array of strings, each being the ID of the record associated with the money amount through this relation, + * @returns {Promise | void>} + * An object that includes the IDs of related records that were restored, such as the ID of associated price set money amounts. + * The object's keys are the ID attribute names of the money amount entity's relations, such as `price_set_money_amount_id`, + * and its value is an array of strings, each being the ID of the record associated with the money amount through this relation, * such as the IDs of associated price set money amounts. * * @example @@ -1324,7 +1329,7 @@ export interface IPricingModuleService { * ) * } */ - restoreDeletedMoneyAmounts( + restoreMoneyAmounts( ids: string[], config?: RestoreReturn, sharedContext?: Context diff --git a/packages/types/src/product/service.ts b/packages/types/src/product/service.ts index 86c4593e16..9477fd31ef 100644 --- a/packages/types/src/product/service.ts +++ b/packages/types/src/product/service.ts @@ -1493,24 +1493,24 @@ export interface IProductModuleService { /** * This method is used to update a product's variants. - * + * * @param {UpdateProductVariantDTO[]} data - The product variants to update. * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. * @returns {Promise} The updated product variants's details. - * + * * @example * import { * initialize as initializeProductModule, * } from "@medusajs/product" - * import { + * import { * UpdateProductVariantDTO * } from "@medusajs/product/dist/types/services/product-variant" - * + * * async function updateProductVariants (items: UpdateProductVariantDTO[]) { * const productModule = await initializeProductModule() - * + * * const productVariants = await productModule.updateVariants(items) - * + * * // do something with the product variants or return them * } */ @@ -1521,24 +1521,24 @@ export interface IProductModuleService { /** * This method is used to create variants for a product. - * + * * @param {CreateProductVariantDTO[]} data - The product variants to create. * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. * @returns {Promise} The created product variants' details. - * + * * @example * import { * initialize as initializeProductModule, * } from "@medusajs/product" - * + * * async function createProductVariants (items: { * product_id: string, * title: string * }[]) { * const productModule = await initializeProductModule() - * + * * const productVariants = await productModule.createVariants(items) - * + * * // do something with the product variants or return them * } */ @@ -2513,16 +2513,16 @@ export interface IProductModuleService { ): Promise | void> /** - * This method is used to restore product varaints that were soft deleted. Product variants are soft deleted when they're not + * This method is used to restore product varaints that were soft deleted. Product variants are soft deleted when they're not * provided in a product's details passed to the {@link update} method. - * + * * @param {string[]} variantIds - The IDs of the variants to restore. - * @param {RestoreReturn} config - + * @param {RestoreReturn} config - * Configurations determining which relations to restore along with each of the product variants. You can pass to its `returnLinkableKeys` * property any of the product variant's relation attribute names. * @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module. * @returns {Promise | void>} - * An object that includes the IDs of related records that were restored. The object's keys are the ID attribute names of the product variant entity's relations + * An object that includes the IDs of related records that were restored. The object's keys are the ID attribute names of the product variant entity's relations * and its value is an array of strings, each being the ID of the record associated with the product variant through this relation. * * If there are no related records that were restored, the promise resolved to `void`. diff --git a/packages/utils/src/common/__tests__/pluralize.spec.ts b/packages/utils/src/common/__tests__/pluralize.spec.ts new file mode 100644 index 0000000000..8f3301bc05 --- /dev/null +++ b/packages/utils/src/common/__tests__/pluralize.spec.ts @@ -0,0 +1,33 @@ +import { pluralize } from "../plurailze" + +describe("pluralize", function () { + it("should pluralize any words", function () { + const words = [ + "apple", + "box", + "day", + "country", + "baby", + "knife", + "hero", + "potato", + "address", + ] + + const expectedOutput = [ + "apples", + "boxes", + "days", + "countries", + "babies", + "knives", + "heroes", + "potatoes", + "addresses", + ] + + words.forEach((word, index) => { + expect(pluralize(word)).toBe(expectedOutput[index]) + }) + }) +}) diff --git a/packages/utils/src/common/index.ts b/packages/utils/src/common/index.ts index 7dc7fd9831..4f47fcc1ea 100644 --- a/packages/utils/src/common/index.ts +++ b/packages/utils/src/common/index.ts @@ -26,6 +26,7 @@ export * from "./object-from-string-path" export * from "./object-to-string-path" export * from "./optional-numeric-serializer" export * from "./pick-value-from-object" +export * from "./plurailze" export * from "./promise-all" export * from "./remote-query-object-from-string" export * from "./remote-query-object-to-string" diff --git a/packages/utils/src/common/plurailze.ts b/packages/utils/src/common/plurailze.ts new file mode 100644 index 0000000000..f35fb2d89b --- /dev/null +++ b/packages/utils/src/common/plurailze.ts @@ -0,0 +1,27 @@ +/** + * Some library provide pluralize function with language specific rules. + * This is a simple implementation of pluralize function. + * @param word + */ +export function pluralize(word: string): string { + // Add basic rules for forming plurals + if ( + //word.endsWith("s") || + word.endsWith("sh") || + word.endsWith("ss") || + word.endsWith("ch") || + word.endsWith("x") || + word.endsWith("o") || + word.endsWith("z") + ) { + return word + "es" + } else if (word.endsWith("y") && !"aeiou".includes(word[word.length - 2])) { + return word.slice(0, -1) + "ies" + } else if (word.endsWith("es")) { + return word + } else if (word.endsWith("fe")) { + return word.slice(0, -2) + "ves" + } else { + return word + "s" + } +} diff --git a/packages/utils/src/dal/index.ts b/packages/utils/src/dal/index.ts index 5085c6d0a3..2d87ea47cf 100644 --- a/packages/utils/src/dal/index.ts +++ b/packages/utils/src/dal/index.ts @@ -3,5 +3,4 @@ export * from "./mikro-orm/mikro-orm-repository" export * from "./mikro-orm/mikro-orm-soft-deletable-filter" export * from "./mikro-orm/utils" export * from "./repositories" -export * from "./repository" export * from "./utils" diff --git a/packages/utils/src/dal/mikro-orm/mikro-orm-repository.ts b/packages/utils/src/dal/mikro-orm/mikro-orm-repository.ts index ea4d185af6..745b047795 100644 --- a/packages/utils/src/dal/mikro-orm/mikro-orm-repository.ts +++ b/packages/utils/src/dal/mikro-orm/mikro-orm-repository.ts @@ -1,6 +1,8 @@ import { + BaseFilterable, Context, DAL, + FilterQuery, FilterQuery as InternalFilterQuery, RepositoryService, RepositoryTransformOptions, @@ -17,11 +19,11 @@ import { EntityName, FilterQuery as MikroFilterQuery, } from "@mikro-orm/core/typings" -import { MedusaError, isString } from "../../common" +import { isString } from "../../common" import { + buildQuery, InjectTransactionManager, MedusaContext, - buildQuery, } from "../../modules-sdk" import { getSoftDeletedCascadedEntitiesIdsMappedBy, @@ -42,10 +44,10 @@ export class MikroOrmBase { : this.manager_) as unknown as TManager } - getActiveManager( - @MedusaContext() - { transactionManager, manager }: Context = {} - ): TManager { + getActiveManager({ + transactionManager, + manager, + }: Context = {}): TManager { return (transactionManager ?? manager ?? this.manager_) as TManager } @@ -77,9 +79,10 @@ export class MikroOrmBase { * related ones. */ -export class MikroOrmBaseRepository< - T extends object = object -> extends MikroOrmBase { +export class MikroOrmBaseRepository + extends MikroOrmBase + implements RepositoryService +{ constructor(...args: any[]) { // @ts-ignore super(...arguments) @@ -89,11 +92,14 @@ export class MikroOrmBaseRepository< throw new Error("Method not implemented.") } - update(data: unknown[], context?: Context): Promise { + update(data: { entity; update }[], context?: Context): Promise { throw new Error("Method not implemented.") } - delete(ids: string[] | object[], context?: Context): Promise { + delete( + idsOrPKs: FilterQuery & BaseFilterable>, + context?: Context + ): Promise { throw new Error("Method not implemented.") } @@ -115,10 +121,10 @@ export class MikroOrmBaseRepository< @InjectTransactionManager() async softDelete( idsOrFilter: string[] | InternalFilterQuery, - @MedusaContext() - { transactionManager: manager }: Context = {} + @MedusaContext() sharedContext: Context = {} ): Promise<[T[], Record]> { const isArray = Array.isArray(idsOrFilter) + // TODO handle composite keys const filter = isArray || isString(idsOrFilter) ? { @@ -128,9 +134,10 @@ export class MikroOrmBaseRepository< } : idsOrFilter - const entities = await this.find({ where: filter as any }) + const entities = await this.find({ where: filter as any }, sharedContext) const date = new Date() + const manager = this.getActiveManager(sharedContext) await mikroOrmUpdateDeletedAtRecursively( manager, entities as any[], @@ -147,9 +154,9 @@ export class MikroOrmBaseRepository< @InjectTransactionManager() async restore( idsOrFilter: string[] | InternalFilterQuery, - @MedusaContext() - { transactionManager: manager }: Context = {} + @MedusaContext() sharedContext: Context = {} ): Promise<[T[], Record]> { + // TODO handle composite keys const isArray = Array.isArray(idsOrFilter) const filter = isArray || isString(idsOrFilter) @@ -164,8 +171,9 @@ export class MikroOrmBaseRepository< withDeleted: true, }) - const entities = await this.find(query) + const entities = await this.find(query, sharedContext) + const manager = this.getActiveManager(sharedContext) await mikroOrmUpdateDeletedAtRecursively(manager, entities as any[], null) const softDeletedEntitiesMap = getSoftDeletedCascadedEntitiesIdsMappedBy({ @@ -228,18 +236,12 @@ export class MikroOrmBaseTreeRepository< } } -type DtoBasedMutationMethods = "create" | "update" - -export function mikroOrmBaseRepositoryFactory< - T extends object = object, - TDTOs extends { [K in DtoBasedMutationMethods]?: any } = { - [K in DtoBasedMutationMethods]?: any - } ->(entity: EntityClass | EntitySchema) { - class MikroOrmAbstractBaseRepository_ - extends MikroOrmBaseRepository - implements RepositoryService - { +export function mikroOrmBaseRepositoryFactory( + entity: any +): { + new ({ manager }: { manager: any }): MikroOrmBaseRepository +} { + class MikroOrmAbstractBaseRepository_ extends MikroOrmBaseRepository { // @ts-ignore constructor(...args: any[]) { // @ts-ignore @@ -257,7 +259,7 @@ export function mikroOrmBaseRepositoryFactory< ) } - async create(data: TDTOs["create"][], context?: Context): Promise { + async create(data: any[], context?: Context): Promise { const manager = this.getActiveManager(context) const entities = data.map((data_) => { @@ -272,76 +274,13 @@ export function mikroOrmBaseRepositoryFactory< return entities } - async update(data: TDTOs["update"][], context?: Context): Promise { - // TODO: Move this logic to the service packages/utils/src/modules-sdk/abstract-service-factory.ts + async update(data: { entity; update }[], context?: Context): Promise { const manager = this.getActiveManager(context) - - const primaryKeys = - MikroOrmAbstractBaseRepository_.retrievePrimaryKeys(entity) - - let primaryKeysCriteria: { [key: string]: any }[] = [] - if (primaryKeys.length === 1) { - primaryKeysCriteria.push({ - [primaryKeys[0]]: data.map((d) => d[primaryKeys[0]]), - }) - } else { - primaryKeysCriteria = data.map((d) => ({ - $and: primaryKeys.map((key) => ({ [key]: d[key] })), - })) - } - - const allEntities = await Promise.all( - primaryKeysCriteria.map( - async (criteria) => - await this.find({ where: criteria } as DAL.FindOptions, context) - ) - ) - - const existingEntities = allEntities.flat() - - const existingEntitiesMap = new Map() - existingEntities.forEach((entity) => { - if (entity) { - const key = - MikroOrmAbstractBaseRepository_.buildUniqueCompositeKeyValue( - primaryKeys, - entity - ) - existingEntitiesMap.set(key, entity) - } - }) - - const missingEntities = data.filter((data_) => { - const key = - MikroOrmAbstractBaseRepository_.buildUniqueCompositeKeyValue( - primaryKeys, - data_ - ) - return !existingEntitiesMap.has(key) - }) - - if (missingEntities.length) { - const entityName = (entity as EntityClass).name ?? entity - const missingEntitiesKeys = data.map((data_) => - primaryKeys.map((key) => data_[key]).join(", ") - ) - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `${entityName} with ${primaryKeys.join( - ", " - )} "${missingEntitiesKeys.join(", ")}" not found` - ) - } - const entities = data.map((data_) => { - const key = - MikroOrmAbstractBaseRepository_.buildUniqueCompositeKeyValue( - primaryKeys, - data_ - ) - const existingEntity = existingEntitiesMap.get(key)! - - return manager.assign(existingEntity, data_ as RequiredEntityData) + return manager.assign( + data_.entity, + data_.update as RequiredEntityData + ) }) manager.persist(entities) @@ -350,40 +289,11 @@ export function mikroOrmBaseRepositoryFactory< } async delete( - primaryKeyValues: string[] | object[], + filters: FilterQuery & BaseFilterable>, context?: Context ): Promise { const manager = this.getActiveManager(context) - - const primaryKeys = - MikroOrmAbstractBaseRepository_.retrievePrimaryKeys(entity) - - let deletionCriteria - if (primaryKeys.length > 1) { - deletionCriteria = { - $or: primaryKeyValues.map((compositeKeyValue) => { - const keys = Object.keys(compositeKeyValue) - if (!primaryKeys.every((k) => keys.includes(k))) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Composite key must contain all primary key fields: ${primaryKeys.join( - ", " - )}. Found: ${keys}` - ) - } - - const criteria: { [key: string]: any } = {} - for (const key of primaryKeys) { - criteria[key] = compositeKeyValue[key] - } - return criteria - }), - } - } else { - deletionCriteria = { [primaryKeys[0]]: { $in: primaryKeyValues } } - } - - await manager.nativeDelete(entity as EntityName, deletionCriteria) + await manager.nativeDelete(entity as EntityName, filters as any) } async find(options?: DAL.FindOptions, context?: Context): Promise { @@ -423,11 +333,7 @@ export function mikroOrmBaseRepositoryFactory< ) } - async upsert( - data: (TDTOs["create"] | TDTOs["update"])[], - context: Context = {} - ): Promise { - // TODO: Move this logic to the service packages/utils/src/modules-sdk/abstract-service-factory.ts + async upsert(data: any[], context: Context = {}): Promise { const manager = this.getActiveManager(context) const primaryKeys = @@ -435,21 +341,34 @@ export function mikroOrmBaseRepositoryFactory< let primaryKeysCriteria: { [key: string]: any }[] = [] if (primaryKeys.length === 1) { - primaryKeysCriteria.push({ - [primaryKeys[0]]: data.map((d) => d[primaryKeys[0]]), - }) + const primaryKeyValues = data + .map((d) => d[primaryKeys[0]]) + .filter(Boolean) + + if (primaryKeyValues.length) { + primaryKeysCriteria.push({ + [primaryKeys[0]]: primaryKeyValues, + }) + } } else { primaryKeysCriteria = data.map((d) => ({ $and: primaryKeys.map((key) => ({ [key]: d[key] })), })) } - const allEntities = await Promise.all( - primaryKeysCriteria.map( - async (criteria) => - await this.find({ where: criteria } as DAL.FindOptions, context) + let allEntities: T[][] = [] + + if (primaryKeysCriteria.length) { + allEntities = await Promise.all( + primaryKeysCriteria.map( + async (criteria) => + await this.find( + { where: criteria } as DAL.FindOptions, + context + ) + ) ) - ) + } const existingEntities = allEntities.flat() @@ -482,7 +401,7 @@ export function mikroOrmBaseRepositoryFactory< const updatedType = manager.assign(existingEntity, data_) updatedEntities.push(updatedType) } else { - const newEntity = manager.create(entity, data_) + const newEntity = manager.create(entity, data_) createdEntities.push(newEntity) } }) @@ -497,9 +416,12 @@ export function mikroOrmBaseRepositoryFactory< upsertedEntities.push(...updatedEntities) } + // TODO return the all, created, updated entities return upsertedEntities } } - return MikroOrmAbstractBaseRepository_ + return MikroOrmAbstractBaseRepository_ as unknown as { + new ({ manager }: { manager: any }): MikroOrmBaseRepository + } } diff --git a/packages/utils/src/dal/mikro-orm/utils.ts b/packages/utils/src/dal/mikro-orm/utils.ts index fc5d1f55d7..43a5a5efa2 100644 --- a/packages/utils/src/dal/mikro-orm/utils.ts +++ b/packages/utils/src/dal/mikro-orm/utils.ts @@ -1,3 +1,5 @@ +import { buildQuery } from "../../modules-sdk" + export const mikroOrmUpdateDeletedAtRecursively = async < T extends object = any >( @@ -27,12 +29,35 @@ export const mikroOrmUpdateDeletedAtRecursively = async < continue } + const retrieveEntity = async () => { + const query = buildQuery( + { + id: entity.id, + }, + { + relations: [relation.name], + withDeleted: true, + } + ) + return await manager.findOne( + entity.constructor.name, + query.where, + query.options + ) + } + + if (!entityRelation) { + // Fixes the case of many to many through pivot table + entityRelation = await retrieveEntity() + } + const isCollection = "toArray" in entityRelation let relationEntities: any[] = [] if (isCollection) { if (!entityRelation.isInitialized()) { - entityRelation = await entityRelation.init({ populate: true }) + entityRelation = await retrieveEntity() + entityRelation = entityRelation[relation.name] } relationEntities = entityRelation.getItems() } else { @@ -53,6 +78,10 @@ export const mikroOrmSerializer = async ( ): Promise => { options ??= {} const { serialize } = await import("@mikro-orm/core") - const result = serialize(data, options) + const result = serialize(data, { + forceObject: true, + populate: true, + ...options, + }) return result as unknown as Promise } diff --git a/packages/utils/src/dal/repository.ts b/packages/utils/src/dal/repository.ts deleted file mode 100644 index f2f3da05a3..0000000000 --- a/packages/utils/src/dal/repository.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { Context, DAL, RepositoryTransformOptions } from "@medusajs/types" -import { MedusaContext } from "../modules-sdk" -import { transactionWrapper } from "./utils" - -class AbstractBase { - protected readonly manager_: any - - protected constructor({ manager }) { - this.manager_ = manager - } - - getActiveManager( - @MedusaContext() - { transactionManager, manager }: Context = {} - ): TManager { - return (transactionManager ?? manager ?? this.manager_) as TManager - } - - async transaction( - task: (transactionManager: TManager) => Promise, - { - transaction, - isolationLevel, - enableNestedTransactions = false, - }: { - isolationLevel?: string - enableNestedTransactions?: boolean - transaction?: TManager - } = {} - ): Promise { - // @ts-ignore - return await transactionWrapper.apply(this, arguments) - } -} - -export abstract class AbstractBaseRepository - extends AbstractBase - implements DAL.RepositoryService -{ - abstract find(options?: DAL.FindOptions, context?: Context) - - abstract findAndCount( - options?: DAL.FindOptions, - context?: Context - ): Promise<[T[], number]> - - abstract create(data: unknown[], context?: Context): Promise - - abstract update(data: unknown[], context?: Context): Promise - - abstract delete(ids: string[], context?: Context): Promise - - abstract upsert(data: unknown[], context?: Context): Promise - - abstract softDelete( - ids: string[], - context?: Context - ): Promise<[T[], Record]> - - abstract restore( - ids: string[], - context?: Context - ): Promise<[T[], Record]> - - abstract getFreshManager(): TManager - - abstract serialize( - data: any, - options?: any - ): Promise -} - -export abstract class AbstractTreeRepositoryBase - extends AbstractBase - implements DAL.TreeRepositoryService -{ - protected constructor({ manager }) { - // @ts-ignore - super(...arguments) - } - - abstract find( - options?: DAL.FindOptions, - transformOptions?: RepositoryTransformOptions, - context?: Context - ) - - abstract findAndCount( - options?: DAL.FindOptions, - transformOptions?: RepositoryTransformOptions, - context?: Context - ): Promise<[T[], number]> - - abstract create(data: unknown, context?: Context): Promise - - abstract delete(id: string, context?: Context): Promise - - abstract getFreshManager(): TManager - - abstract serialize( - data: any, - options?: any - ): Promise -} diff --git a/packages/utils/src/modules-sdk/__tests__/abstract-module-service-factory.spec.ts b/packages/utils/src/modules-sdk/__tests__/abstract-module-service-factory.spec.ts new file mode 100644 index 0000000000..35935e84ed --- /dev/null +++ b/packages/utils/src/modules-sdk/__tests__/abstract-module-service-factory.spec.ts @@ -0,0 +1,201 @@ +import { abstractModuleServiceFactory } from "../abstract-module-service-factory" + +const baseRepoMock = { + serialize: jest.fn().mockImplementation((item) => item), + transaction: (task) => task("transactionManager"), + getFreshManager: jest.fn().mockReturnThis(), +} + +const defaultContext = { __type: "MedusaContext", manager: baseRepoMock } +const defaultTransactionContext = { + __type: "MedusaContext", + transactionManager: "transactionManager", +} + +describe("Abstract Module Service Factory", () => { + const containerMock = { + baseRepository: baseRepoMock, + mainModelMockRepository: baseRepoMock, + otherModelMock1Repository: baseRepoMock, + otherModelMock2Repository: baseRepoMock, + mainModelMockService: { + retrieve: jest.fn().mockResolvedValue({ id: "1", name: "Item" }), + list: jest.fn().mockResolvedValue([{ id: "1", name: "Item" }]), + delete: jest.fn().mockResolvedValue(undefined), + softDelete: jest.fn().mockResolvedValue([[], {}]), + restore: jest.fn().mockResolvedValue([[], {}]), + }, + otherModelMock1Service: { + retrieve: jest.fn().mockResolvedValue({ id: "1", name: "Item" }), + list: jest.fn().mockResolvedValue([{ id: "1", name: "Item" }]), + delete: jest.fn().mockResolvedValue(undefined), + softDelete: jest.fn().mockResolvedValue([[], {}]), + restore: jest.fn().mockResolvedValue([[], {}]), + }, + otherModelMock2Service: { + retrieve: jest.fn().mockResolvedValue({ id: "1", name: "Item" }), + list: jest.fn().mockResolvedValue([{ id: "1", name: "Item" }]), + delete: jest.fn().mockResolvedValue(undefined), + softDelete: jest.fn().mockResolvedValue([[], {}]), + restore: jest.fn().mockResolvedValue([[], {}]), + }, + } + + const mainModelMock = class MainModelMock {} + const otherModelMock1 = class OtherModelMock1 {} + const otherModelMock2 = class OtherModelMock2 {} + + const abstractModuleService = abstractModuleServiceFactory< + any, + any, + { + OtherModelMock1: { + dto: any + singular: "OtherModelMock1" + plural: "OtherModelMock1s" + } + OtherModelMock2: { + dto: any + singular: "OtherModelMock2" + plural: "OtherModelMock2s" + } + } + >( + mainModelMock, + [ + { + model: otherModelMock1, + plural: "otherModelMock1s", + singular: "otherModelMock1", + }, + { + model: otherModelMock2, + plural: "otherModelMock2s", + singular: "otherModelMock2", + }, + ] + // Add more parameters as needed + ) + + describe("Main Model Methods", () => { + let instance + + beforeEach(() => { + jest.clearAllMocks() + instance = new abstractModuleService(containerMock) + }) + + test("should have retrieve method", async () => { + const result = await instance.retrieve("1") + expect(result).toEqual({ id: "1", name: "Item" }) + expect(containerMock.mainModelMockService.retrieve).toHaveBeenCalledWith( + "1", + undefined, + defaultContext + ) + }) + + test("should have list method", async () => { + const result = await instance.list() + expect(result).toEqual([{ id: "1", name: "Item" }]) + expect(containerMock.mainModelMockService.list).toHaveBeenCalledWith( + {}, + {}, + defaultContext + ) + }) + + test("should have delete method", async () => { + await instance.delete("1") + expect(containerMock.mainModelMockService.delete).toHaveBeenCalledWith( + ["1"], + defaultTransactionContext + ) + }) + + test("should have softDelete method", async () => { + const result = await instance.softDelete("1") + expect(result).toEqual(undefined) + expect( + containerMock.mainModelMockService.softDelete + ).toHaveBeenCalledWith(["1"], defaultTransactionContext) + }) + + test("should have restore method", async () => { + const result = await instance.restore("1") + expect(result).toEqual(undefined) + expect(containerMock.mainModelMockService.restore).toHaveBeenCalledWith( + ["1"], + defaultTransactionContext + ) + }) + + test("should have delete method with selector", async () => { + await instance.delete({ selector: { id: "1" } }) + expect(containerMock.mainModelMockService.delete).toHaveBeenCalledWith( + [{ selector: { id: "1" } }], + defaultTransactionContext + ) + }) + }) + + describe("Other Models Methods", () => { + let instance + + beforeEach(() => { + jest.clearAllMocks() + instance = new abstractModuleService(containerMock) + }) + + test("should have retrieve method for other models", async () => { + const result = await instance.retrieveOtherModelMock1("1") + expect(result).toEqual({ id: "1", name: "Item" }) + expect( + containerMock.otherModelMock1Service.retrieve + ).toHaveBeenCalledWith("1", undefined, defaultContext) + }) + + test("should have list method for other models", async () => { + const result = await instance.listOtherModelMock1s() + expect(result).toEqual([{ id: "1", name: "Item" }]) + expect(containerMock.otherModelMock1Service.list).toHaveBeenCalledWith( + {}, + {}, + defaultContext + ) + }) + + test("should have delete method for other models", async () => { + await instance.deleteOtherModelMock1s("1") + expect(containerMock.otherModelMock1Service.delete).toHaveBeenCalledWith( + ["1"], + defaultTransactionContext + ) + }) + + test("should have softDelete method for other models", async () => { + const result = await instance.softDeleteOtherModelMock1s("1") + expect(result).toEqual(undefined) + expect( + containerMock.otherModelMock1Service.softDelete + ).toHaveBeenCalledWith(["1"], defaultTransactionContext) + }) + + test("should have restore method for other models", async () => { + const result = await instance.restoreOtherModelMock1s("1") + expect(result).toEqual(undefined) + expect(containerMock.otherModelMock1Service.restore).toHaveBeenCalledWith( + ["1"], + defaultTransactionContext + ) + }) + + test("should have delete method for other models with selector", async () => { + await instance.deleteOtherModelMock1s({ selector: { id: "1" } }) + expect(containerMock.otherModelMock1Service.delete).toHaveBeenCalledWith( + [{ selector: { id: "1" } }], + defaultTransactionContext + ) + }) + }) +}) diff --git a/packages/utils/src/modules-sdk/__tests__/internal-module-service-factory.spec.ts b/packages/utils/src/modules-sdk/__tests__/internal-module-service-factory.spec.ts new file mode 100644 index 0000000000..2e4b9db5c4 --- /dev/null +++ b/packages/utils/src/modules-sdk/__tests__/internal-module-service-factory.spec.ts @@ -0,0 +1,240 @@ +import { internalModuleServiceFactory } from "../internal-module-service-factory" +import { lowerCaseFirst } from "../../common" + +const defaultContext = { __type: "MedusaContext" } + +class Model {} +describe("Internal Module Service Factory", () => { + const modelRepositoryName = `${lowerCaseFirst(Model.name)}Repository` + + const containerMock = { + [modelRepositoryName]: { + transaction: (task) => task(), + getFreshManager: jest.fn().mockReturnThis(), + find: jest.fn(), + findAndCount: jest.fn(), + create: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + softDelete: jest.fn(), + restore: jest.fn(), + upsert: jest.fn(), + }, + [`composite${Model.name}Repository`]: { + transaction: (task) => task(), + getFreshManager: jest.fn().mockReturnThis(), + find: jest.fn(), + findAndCount: jest.fn(), + create: jest.fn(), + update: jest.fn(), + delete: jest.fn(), + softDelete: jest.fn(), + restore: jest.fn(), + upsert: jest.fn(), + }, + } + + const internalModuleService = internalModuleServiceFactory(Model) + + describe("Internal Module Service Methods", () => { + let instance + + beforeEach(() => { + jest.clearAllMocks() + instance = new internalModuleService(containerMock) + }) + + test("should throw model id undefined error on retrieve if id is not defined", async () => { + const err = await instance.retrieve().catch((e) => e) + expect(err.message).toBe("model - id must be defined") + }) + + test("should throw an error on retrieve if composite key values are not defined", async () => { + class CompositeModel { + id: string + name: string + + static meta = { primaryKeys: ["id", "name"] } + } + + const compositeInternalModuleService = + internalModuleServiceFactory(CompositeModel) + + const instance = new compositeInternalModuleService(containerMock) + + const err = await instance.retrieve().catch((e) => e) + expect(err.message).toBe("compositeModel - id, name must be defined") + }) + + test("should throw NOT_FOUND error on retrieve if entity not found", async () => { + containerMock[modelRepositoryName].find.mockResolvedValueOnce([]) + + const err = await instance.retrieve("1").catch((e) => e) + expect(err.message).toBe("Model with id: 1 was not found") + }) + + test("should retrieve entity successfully", async () => { + const entity = { id: "1", name: "Item" } + containerMock[modelRepositoryName].find.mockResolvedValueOnce([entity]) + + const result = await instance.retrieve("1") + expect(result).toEqual(entity) + }) + + test("should retrieve entity successfully with composite key", async () => { + class CompositeModel { + id: string + name: string + + static meta = { primaryKeys: ["id", "name"] } + } + + const compositeInternalModuleService = + internalModuleServiceFactory(CompositeModel) + + const instance = new compositeInternalModuleService(containerMock) + + const entity = { id: "1", name: "Item" } + containerMock[ + `${lowerCaseFirst(CompositeModel.name)}Repository` + ].find.mockResolvedValueOnce([entity]) + + const result = await instance.retrieve({ id: "1", name: "Item" }) + expect(result).toEqual(entity) + }) + + test("should list entities successfully", async () => { + const entities = [ + { id: "1", name: "Item" }, + { id: "2", name: "Item2" }, + ] + containerMock[modelRepositoryName].find.mockResolvedValueOnce(entities) + + const result = await instance.list() + expect(result).toEqual(entities) + }) + + test("should list and count entities successfully", async () => { + const entities = [ + { id: "1", name: "Item" }, + { id: "2", name: "Item2" }, + ] + const count = entities.length + containerMock[modelRepositoryName].findAndCount.mockResolvedValueOnce([ + entities, + count, + ]) + + const result = await instance.listAndCount() + expect(result).toEqual([entities, count]) + }) + + test("should create entity successfully", async () => { + const entity = { id: "1", name: "Item" } + + containerMock[modelRepositoryName].find.mockReturnValue([entity]) + + containerMock[modelRepositoryName].create.mockImplementation( + async (entity) => entity + ) + + const result = await instance.create(entity) + expect(result).toEqual(entity) + }) + + test("should create entities successfully", async () => { + const entities = [ + { id: "1", name: "Item" }, + { id: "2", name: "Item2" }, + ] + + containerMock[modelRepositoryName].find.mockResolvedValueOnce([entities]) + + containerMock[modelRepositoryName].create.mockResolvedValueOnce(entities) + + const result = await instance.create(entities) + expect(result).toEqual(entities) + }) + + test("should update entity successfully", async () => { + const updateData = { id: "1", name: "UpdatedItem" } + + containerMock[modelRepositoryName].find.mockResolvedValueOnce([ + updateData, + ]) + + containerMock[modelRepositoryName].update.mockResolvedValueOnce([ + updateData, + ]) + + const result = await instance.update(updateData) + expect(result).toEqual([updateData]) + }) + + test("should update entities successfully", async () => { + const updateData = { id: "1", name: "UpdatedItem" } + const entitiesToUpdate = [{ id: "1", name: "Item" }] + + containerMock[modelRepositoryName].find.mockResolvedValueOnce( + entitiesToUpdate + ) + + containerMock[modelRepositoryName].update.mockResolvedValueOnce([ + { entity: entitiesToUpdate[0], update: updateData }, + ]) + + const result = await instance.update({ selector: {}, data: updateData }) + expect(result).toEqual([ + { entity: entitiesToUpdate[0], update: updateData }, + ]) + }) + + test("should delete entity successfully", async () => { + await instance.delete("1") + expect(containerMock[modelRepositoryName].delete).toHaveBeenCalledWith( + { + $or: [ + { + id: "1", + }, + ], + }, + defaultContext + ) + }) + + test("should delete entities successfully", async () => { + const entitiesToDelete = [{ id: "1", name: "Item" }] + containerMock[modelRepositoryName].find.mockResolvedValueOnce( + entitiesToDelete + ) + + await instance.delete({ selector: {} }) + expect(containerMock[modelRepositoryName].delete).toHaveBeenCalledWith( + { + $or: [ + { + id: "1", + }, + ], + }, + defaultContext + ) + }) + + test("should soft delete entity successfully", async () => { + await instance.softDelete("1") + expect( + containerMock[modelRepositoryName].softDelete + ).toHaveBeenCalledWith("1", defaultContext) + }) + + test("should restore entity successfully", async () => { + await instance.restore("1") + expect(containerMock[modelRepositoryName].restore).toHaveBeenCalledWith( + "1", + defaultContext + ) + }) + }) +}) diff --git a/packages/utils/src/modules-sdk/abstract-module-service-factory.ts b/packages/utils/src/modules-sdk/abstract-module-service-factory.ts new file mode 100644 index 0000000000..e6e23257df --- /dev/null +++ b/packages/utils/src/modules-sdk/abstract-module-service-factory.ts @@ -0,0 +1,527 @@ +/** + * Utility factory and interfaces for module service public facing API + */ +import { + Constructor, + Context, + FindConfig, + IEventBusModuleService, + Pluralize, + RepositoryService, + RestoreReturn, + SoftDeleteReturn, +} from "@medusajs/types" +import { + isString, + kebabCase, + lowerCaseFirst, + mapObjectTo, + MapToConfig, + pluralize, + upperCaseFirst, +} from "../common" +import { + InjectManager, + InjectTransactionManager, + MedusaContext, +} from "./decorators" + +type BaseMethods = + | "retrieve" + | "list" + | "listAndCount" + | "delete" + | "softDelete" + | "restore" + +const readMethods = ["retrieve", "list", "listAndCount"] as BaseMethods[] +const writeMethods = ["delete", "softDelete", "restore"] as BaseMethods[] + +const methods: BaseMethods[] = [...readMethods, ...writeMethods] + +type ModelsConfigTemplate = { + [ModelName: string]: { singular?: string; plural?: string; dto: object } +} + +type ExtractSingularName< + T extends Record, + K = keyof T +> = T[K] extends { singular?: string } ? T[K]["singular"] : K + +type ExtractPluralName, K = keyof T> = T[K] extends { + plural?: string +} + ? T[K]["plural"] + : Pluralize + +type ModelConfiguration = + | Constructor + | { singular?: string; plural?: string; model: Constructor } + +export interface AbstractModuleServiceBase { + get __container__(): TContainer + + retrieve( + id: string, + config?: FindConfig, + sharedContext?: Context + ): Promise + + list( + filters?: any, + config?: FindConfig, + sharedContext?: Context + ): Promise + + listAndCount( + filters?: any, + config?: FindConfig, + sharedContext?: Context + ): Promise<[TMainModelDTO[], number]> + + delete( + primaryKeyValues: string | object | string[] | object[], + sharedContext?: Context + ): Promise + + softDelete( + primaryKeyValues: string | object | string[] | object[], + config?: SoftDeleteReturn, + sharedContext?: Context + ): Promise | void> + + restore( + primaryKeyValues: string | object | string[] | object[], + config?: RestoreReturn, + sharedContext?: Context + ): Promise | void> +} + +/** + * Multiple issues on typescript around mapped types function are open, so + * when overriding a method from the base class that is mapped dynamically from the + * other models, we will have to ignore the error (2425) + * + * see: https://github.com/microsoft/TypeScript/issues/48125 + */ +export type AbstractModuleService< + TContainer, + TMainModelDTO, + TOtherModelNamesAndAssociatedDTO extends ModelsConfigTemplate +> = AbstractModuleServiceBase & { + [K in keyof TOtherModelNamesAndAssociatedDTO as `retrieve${ExtractSingularName< + TOtherModelNamesAndAssociatedDTO, + K + > & + string}`]: ( + id: string, + config?: FindConfig, + sharedContext?: Context + ) => Promise +} & { + [K in keyof TOtherModelNamesAndAssociatedDTO as `list${ExtractPluralName< + TOtherModelNamesAndAssociatedDTO, + K + > & + string}`]: ( + filters?: any, + config?: FindConfig, + sharedContext?: Context + ) => Promise +} & { + [K in keyof TOtherModelNamesAndAssociatedDTO as `listAndCount${ExtractPluralName< + TOtherModelNamesAndAssociatedDTO, + K + > & + string}`]: { + (filters?: any, config?: FindConfig, sharedContext?: Context): Promise< + [TOtherModelNamesAndAssociatedDTO[K & string]["dto"][], number] + > + } +} & { + [K in keyof TOtherModelNamesAndAssociatedDTO as `delete${ExtractPluralName< + TOtherModelNamesAndAssociatedDTO, + K + > & + string}`]: { + ( + primaryKeyValues: string | object | string[] | object[], + sharedContext?: Context + ): Promise + } +} & { + [K in keyof TOtherModelNamesAndAssociatedDTO as `softDelete${ExtractPluralName< + TOtherModelNamesAndAssociatedDTO, + K + > & + string}`]: { + ( + primaryKeyValues: string | object | string[] | object[], + config?: SoftDeleteReturn, + sharedContext?: Context + ): Promise | void> + } +} & { + [K in keyof TOtherModelNamesAndAssociatedDTO as `restore${ExtractPluralName< + TOtherModelNamesAndAssociatedDTO, + K + > & + string}`]: { + ( + primaryKeyValues: string | object | string[] | object[], + config?: RestoreReturn, + sharedContext?: Context + ): Promise | void> + } +} + +/** + * Factory function for creating an abstract module service + * + * @example + * + * const otherModels = new Set([ + * Currency, + * MoneyAmount, + * PriceList, + * PriceListRule, + * PriceListRuleValue, + * PriceRule, + * PriceSetMoneyAmount, + * PriceSetMoneyAmountRules, + * PriceSetRuleType, + * RuleType, + * ]) + * + * const AbstractModuleService = ModulesSdkUtils.abstractModuleServiceFactory< + * InjectedDependencies, + * PricingTypes.PriceSetDTO, + * // The configuration of each entity also accept singular/plural properties, if not provided then it is using english pluralization + * { + * Currency: { dto: PricingTypes.CurrencyDTO } + * MoneyAmount: { dto: PricingTypes.MoneyAmountDTO } + * PriceSetMoneyAmount: { dto: PricingTypes.PriceSetMoneyAmountDTO } + * PriceSetMoneyAmountRules: { + * dto: PricingTypes.PriceSetMoneyAmountRulesDTO + * } + * PriceRule: { dto: PricingTypes.PriceRuleDTO } + * RuleType: { dto: PricingTypes.RuleTypeDTO } + * PriceList: { dto: PricingTypes.PriceListDTO } + * PriceListRule: { dto: PricingTypes.PriceListRuleDTO } + * } + * >(PriceSet, [...otherModels], entityNameToLinkableKeysMap) + * + * @param mainModel + * @param otherModels + * @param entityNameToLinkableKeysMap + */ +export function abstractModuleServiceFactory< + TContainer, + TMainModelDTO, + TOtherModelNamesAndAssociatedDTO extends ModelsConfigTemplate +>( + mainModel: Constructor, + otherModels: ModelConfiguration[], + entityNameToLinkableKeysMap: MapToConfig = {} +): { + new (container: TContainer): AbstractModuleService< + TContainer, + TMainModelDTO, + TOtherModelNamesAndAssociatedDTO + > +} { + const buildMethodNamesFromModel = ( + model: ModelConfiguration, + suffixed: boolean = true + ): Record => { + return methods.reduce((acc, method) => { + let modelName: string = "" + + if (method === "retrieve") { + modelName = + "singular" in model && model.singular + ? model.singular + : (model as Constructor).name + } else { + modelName = + "plural" in model && model.plural + ? model.plural + : pluralize((model as Constructor).name) + } + + const methodName = suffixed + ? `${method}${upperCaseFirst(modelName)}` + : method + + return { ...acc, [method]: methodName } + }, {}) + } + + const buildAndAssignMethodImpl = function ( + klassPrototype: any, + method: string, + methodName: string, + model: Constructor + ): void { + const serviceRegistrationName = `${lowerCaseFirst(model.name)}Service` + + const applyMethod = function (impl: Function, contextIndex) { + klassPrototype[methodName] = impl + + const descriptorMockRef = { + value: klassPrototype[methodName], + } + + MedusaContext()(klassPrototype, methodName, contextIndex) + + const ManagerDecorator = readMethods.includes(method as BaseMethods) + ? InjectManager + : InjectTransactionManager + + ManagerDecorator("baseRepository_")( + klassPrototype, + methodName, + descriptorMockRef + ) + + klassPrototype[methodName] = descriptorMockRef.value + } + + let methodImplementation: any = function () { + void 0 + } + + switch (method) { + case "retrieve": + methodImplementation = async function ( + this: AbstractModuleService_, + id: string, + config?: FindConfig, + sharedContext: Context = {} + ): Promise { + const entities = await this.__container__[ + serviceRegistrationName + ].retrieve(id, config, sharedContext) + + return await this.baseRepository_.serialize(entities, { + populate: true, + }) + } + + applyMethod(methodImplementation, 2) + + break + case "list": + methodImplementation = async function ( + this: AbstractModuleService_, + filters = {}, + config: FindConfig = {}, + sharedContext: Context = {} + ): Promise { + const entities = await this.__container__[ + serviceRegistrationName + ].list(filters, config, sharedContext) + + return await this.baseRepository_.serialize(entities, { + populate: true, + }) + } + + applyMethod(methodImplementation, 2) + + break + case "listAndCount": + methodImplementation = async function ( + this: AbstractModuleService_, + filters = {}, + config: FindConfig = {}, + sharedContext: Context = {} + ): Promise { + const [entities, count] = await this.__container__[ + serviceRegistrationName + ].listAndCount(filters, config, sharedContext) + + return [ + await this.baseRepository_.serialize(entities, { + populate: true, + }), + count, + ] + } + + applyMethod(methodImplementation, 2) + + break + case "delete": + methodImplementation = async function ( + this: AbstractModuleService_, + primaryKeyValues: string | object | string[] | object[], + sharedContext: Context = {} + ): Promise { + const primaryKeyValues_ = Array.isArray(primaryKeyValues) + ? primaryKeyValues + : [primaryKeyValues] + await this.__container__[serviceRegistrationName].delete( + primaryKeyValues_, + sharedContext + ) + + await this.eventBusModuleService_?.emit( + primaryKeyValues_.map((primaryKeyValue) => ({ + eventName: `${kebabCase(model.name)}.deleted`, + data: isString(primaryKeyValue) + ? { id: primaryKeyValue } + : primaryKeyValue, + })) + ) + } + + applyMethod(methodImplementation, 1) + + break + case "softDelete": + methodImplementation = async function ( + this: AbstractModuleService_, + primaryKeyValues: string | object | string[] | object[], + config: SoftDeleteReturn = {}, + sharedContext: Context = {} + ): Promise | void> { + const primaryKeyValues_ = Array.isArray(primaryKeyValues) + ? primaryKeyValues + : [primaryKeyValues] + + const [entities, cascadedEntitiesMap] = await this.__container__[ + serviceRegistrationName + ].softDelete(primaryKeyValues_, sharedContext) + + const softDeletedEntities = await this.baseRepository_.serialize( + entities, + { + populate: true, + } + ) + + await this.eventBusModuleService_?.emit( + softDeletedEntities.map(({ id }) => ({ + eventName: `${kebabCase(model.name)}.deleted`, + data: { id }, + })) + ) + + let mappedCascadedEntitiesMap + if (config.returnLinkableKeys) { + // Map internal table/column names to their respective external linkable keys + // eg: product.id = product_id, variant.id = variant_id + mappedCascadedEntitiesMap = mapObjectTo( + cascadedEntitiesMap, + entityNameToLinkableKeysMap, + { + pick: config.returnLinkableKeys, + } + ) + } + + return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 + } + + applyMethod(methodImplementation, 2) + + break + case "restore": + methodImplementation = async function ( + this: AbstractModuleService_, + primaryKeyValues: string | object | string[] | object[], + config: RestoreReturn = {}, + sharedContext: Context = {} + ): Promise | void> { + const primaryKeyValues_ = Array.isArray(primaryKeyValues) + ? primaryKeyValues + : [primaryKeyValues] + + const [_, cascadedEntitiesMap] = await this.__container__[ + serviceRegistrationName + ].restore(primaryKeyValues_, sharedContext) + + let mappedCascadedEntitiesMap + if (config.returnLinkableKeys) { + // Map internal table/column names to their respective external linkable keys + // eg: product.id = product_id, variant.id = variant_id + mappedCascadedEntitiesMap = mapObjectTo( + cascadedEntitiesMap, + entityNameToLinkableKeysMap, + { + pick: config.returnLinkableKeys, + } + ) + } + + return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 + } + + applyMethod(methodImplementation, 2) + + break + } + } + + class AbstractModuleService_ { + readonly __container__: Record + readonly baseRepository_: RepositoryService + readonly eventBusModuleService_: IEventBusModuleService; + + [key: string]: any + + constructor(container: Record) { + this.__container__ = container + this.baseRepository_ = container.baseRepository + + try { + this.eventBusModuleService_ = container.eventBusModuleService + } catch { + /* ignore */ + } + } + } + + const mainModelMethods = buildMethodNamesFromModel(mainModel, false) + + /** + * Build the main retrieve/list/listAndCount/delete/softDelete/restore methods for the main model + */ + + for (let [method, methodName] of Object.entries(mainModelMethods)) { + buildAndAssignMethodImpl( + AbstractModuleService_.prototype, + method, + methodName, + mainModel + ) + } + + /** + * Build the retrieve/list/listAndCount/delete/softDelete/restore methods for all the other models + */ + + const otherModelsMethods: [ModelConfiguration, Record][] = + otherModels.map((model) => [model, buildMethodNamesFromModel(model)]) + + for (let [model, modelsMethods] of otherModelsMethods) { + Object.entries(modelsMethods).forEach(([method, methodName]) => { + model = "model" in model ? model.model : model + buildAndAssignMethodImpl( + AbstractModuleService_.prototype, + method, + methodName, + model + ) + }) + } + + return AbstractModuleService_ as unknown as new ( + container: TContainer + ) => AbstractModuleService< + TContainer, + TMainModelDTO, + TOtherModelNamesAndAssociatedDTO + > +} diff --git a/packages/utils/src/modules-sdk/abstract-service-factory.ts b/packages/utils/src/modules-sdk/abstract-service-factory.ts deleted file mode 100644 index 64a6531bb3..0000000000 --- a/packages/utils/src/modules-sdk/abstract-service-factory.ts +++ /dev/null @@ -1,257 +0,0 @@ -import { - Context, - FindConfig, - FilterQuery as InternalFilterQuery, -} from "@medusajs/types" -import { EntitySchema } from "@mikro-orm/core" -import { EntityClass } from "@mikro-orm/core/typings" -import { - MedusaError, - doNotForceTransaction, - isDefined, - isString, - lowerCaseFirst, - shouldForceTransaction, - upperCaseFirst, -} from "../common" -import { MedusaContext } from "../modules-sdk" -import { buildQuery } from "./build-query" -import { InjectManager, InjectTransactionManager } from "./decorators" - -/** - * Utility factory and interfaces for internal module services - */ - -type FilterableMethods = "list" | "listAndCount" -type Methods = "create" | "update" - -export interface AbstractService< - TEntity extends {}, - TContainer extends object = object, - TDTOs extends { [K in Methods]?: any } = { [K in Methods]?: any }, - TFilters extends { [K in FilterableMethods]?: any } = { - [K in FilterableMethods]?: any - } -> { - get __container__(): TContainer - - retrieve( - id: string, - config?: FindConfig, - sharedContext?: Context - ): Promise - list( - filters?: TFilters["list"], - config?: FindConfig, - sharedContext?: Context - ): Promise - listAndCount( - filters?: TFilters["listAndCount"], - config?: FindConfig, - sharedContext?: Context - ): Promise<[TEntity[], number]> - create(data: TDTOs["create"][], sharedContext?: Context): Promise - update(data: TDTOs["update"][], sharedContext?: Context): Promise - delete( - primaryKeyValues: string[] | object[], - sharedContext?: Context - ): Promise - softDelete( - idsOrFilter: string[] | InternalFilterQuery, - sharedContext?: Context - ): Promise<[TEntity[], Record]> - restore( - idsOrFilter: string[] | InternalFilterQuery, - sharedContext?: Context - ): Promise<[TEntity[], Record]> - upsert( - data: (TDTOs["create"] | TDTOs["update"])[], - sharedContext?: Context - ): Promise -} - -export function abstractServiceFactory< - TContainer extends object = object, - TDTOs extends { [K in Methods]?: any } = { [K in Methods]?: any }, - TFilters extends { [K in FilterableMethods]?: any } = { - [K in FilterableMethods]?: any - } ->( - model: new (...args: any[]) => any -): { - new (container: TContainer): AbstractService< - TEntity, - TContainer, - TDTOs, - TFilters - > -} { - const injectedRepositoryName = `${lowerCaseFirst(model.name)}Repository` - const propertyRepositoryName = `__${injectedRepositoryName}__` - - class AbstractService_ - implements AbstractService - { - readonly __container__: TContainer; - [key: string]: any - - constructor(container: TContainer) { - this.__container__ = container - this[propertyRepositoryName] = container[injectedRepositoryName] - } - - static retrievePrimaryKeys(entity: EntityClass | EntitySchema) { - return ( - (entity as EntitySchema).meta?.primaryKeys ?? - (entity as EntityClass).prototype.__meta?.primaryKeys ?? ["id"] - ) - } - - @InjectManager(propertyRepositoryName) - async retrieve( - primaryKeyValues: string | string[] | object[], - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const primaryKeys = AbstractService_.retrievePrimaryKeys(model) - - if (!isDefined(primaryKeyValues)) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `${ - primaryKeys.length === 1 - ? `"${ - lowerCaseFirst(model.name) + upperCaseFirst(primaryKeys[0]) - }"` - : `${lowerCaseFirst(model.name)} ${primaryKeys.join(", ")}` - } must be defined` - ) - } - - let primaryKeysCriteria = {} - if (primaryKeys.length === 1) { - primaryKeysCriteria[primaryKeys[0]] = primaryKeyValues - } else { - primaryKeysCriteria = (primaryKeyValues as string[] | object[]).map( - (primaryKeyValue) => ({ - $and: primaryKeys.map((key) => ({ [key]: primaryKeyValue[key] })), - }) - ) - } - - const queryOptions = buildQuery(primaryKeysCriteria, config) - - const entities = await this[propertyRepositoryName].find( - queryOptions, - sharedContext - ) - - if (!entities?.length) { - throw new MedusaError( - MedusaError.Types.NOT_FOUND, - `${model.name} with ${primaryKeys.join(", ")}: ${ - Array.isArray(primaryKeyValues) - ? primaryKeyValues.map((v) => - [isString(v) ? v : Object.values(v)].join(", ") - ) - : primaryKeyValues - } was not found` - ) - } - - return entities[0] - } - - @InjectManager(propertyRepositoryName) - async list( - filters: TFilters["list"] = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise { - const queryOptions = buildQuery(filters, config) - - return (await this[propertyRepositoryName].find( - queryOptions, - sharedContext - )) as TEntity[] - } - - @InjectManager(propertyRepositoryName) - async listAndCount( - filters: TFilters["listAndCount"] = {}, - config: FindConfig = {}, - @MedusaContext() sharedContext: Context = {} - ): Promise<[TEntity[], number]> { - const queryOptions = buildQuery(filters, config) - - return (await this[propertyRepositoryName].findAndCount( - queryOptions, - sharedContext - )) as [TEntity[], number] - } - - @InjectTransactionManager(shouldForceTransaction, propertyRepositoryName) - async create( - data: TDTOs["create"][], - @MedusaContext() sharedContext: Context = {} - ): Promise { - return (await this[propertyRepositoryName].create( - data, - sharedContext - )) as TEntity[] - } - - @InjectTransactionManager(shouldForceTransaction, propertyRepositoryName) - async update( - data: TDTOs["update"][], - @MedusaContext() sharedContext: Context = {} - ): Promise { - return (await this[propertyRepositoryName].update( - data, - sharedContext - )) as TEntity[] - } - - @InjectTransactionManager(doNotForceTransaction, propertyRepositoryName) - async delete( - primaryKeyValues: string[] | object[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - await this[propertyRepositoryName].delete(primaryKeyValues, sharedContext) - } - - @InjectTransactionManager(propertyRepositoryName) - async softDelete( - idsOrFilter: string[] | InternalFilterQuery, - @MedusaContext() sharedContext: Context = {} - ): Promise<[TEntity[], Record]> { - return await this[propertyRepositoryName].softDelete( - idsOrFilter, - sharedContext - ) - } - - @InjectTransactionManager(propertyRepositoryName) - async restore( - idsOrFilter: string[] | InternalFilterQuery, - @MedusaContext() sharedContext: Context = {} - ): Promise<[TEntity[], Record]> { - return await this[propertyRepositoryName].restore( - idsOrFilter, - sharedContext - ) - } - - @InjectTransactionManager(propertyRepositoryName) - async upsert( - data: (TDTOs["create"] | TDTOs["update"])[], - @MedusaContext() sharedContext: Context = {} - ): Promise { - return await this[propertyRepositoryName].upsert(data, sharedContext) - } - } - - return AbstractService_ as unknown as new ( - container: TContainer - ) => AbstractService -} diff --git a/packages/utils/src/modules-sdk/decorators/inject-manager.ts b/packages/utils/src/modules-sdk/decorators/inject-manager.ts index 0b40acfd1d..d83c1deee4 100644 --- a/packages/utils/src/modules-sdk/decorators/inject-manager.ts +++ b/packages/utils/src/modules-sdk/decorators/inject-manager.ts @@ -1,4 +1,5 @@ import { Context } from "@medusajs/types" +import { MedusaContextType } from "./context-parameter" export function InjectManager(managerProperty?: string): MethodDecorator { return function ( @@ -37,8 +38,14 @@ export function InjectManager(managerProperty?: string): MethodDecorator { ? this : this[managerProperty] - copiedContext.manager ??= resourceWithManager.getFreshManager() - copiedContext.transactionManager ??= originalContext?.transactionManager + copiedContext.manager = + originalContext.manager ?? resourceWithManager.getFreshManager() + + if (originalContext?.transactionManager) { + copiedContext.transactionManager = originalContext?.transactionManager + } + + copiedContext.__type = MedusaContextType args[argIndex] = copiedContext diff --git a/packages/utils/src/modules-sdk/decorators/inject-transaction-manager.ts b/packages/utils/src/modules-sdk/decorators/inject-transaction-manager.ts index 4387cfb982..580304467e 100644 --- a/packages/utils/src/modules-sdk/decorators/inject-transaction-manager.ts +++ b/packages/utils/src/modules-sdk/decorators/inject-transaction-manager.ts @@ -60,9 +60,13 @@ export function InjectTransactionManager( }) } - copiedContext.transactionManager ??= transactionManager - copiedContext.manager ??= originalContext?.manager - copiedContext.__type ??= MedusaContextType + copiedContext.transactionManager = transactionManager + + if (originalContext?.manager) { + copiedContext.manager = originalContext?.manager + } + + copiedContext.__type = MedusaContextType args[argIndex] = copiedContext diff --git a/packages/utils/src/modules-sdk/index.ts b/packages/utils/src/modules-sdk/index.ts index f4c31ebb23..8837a26b11 100644 --- a/packages/utils/src/modules-sdk/index.ts +++ b/packages/utils/src/modules-sdk/index.ts @@ -5,4 +5,5 @@ export * from "./loaders/mikro-orm-connection-loader" export * from "./loaders/container-loader-factory" export * from "./create-pg-connection" export * from "./migration-scripts" -export * from "./abstract-service-factory" +export * from "./internal-module-service-factory" +export * from "./abstract-module-service-factory" diff --git a/packages/utils/src/modules-sdk/internal-module-service-factory.ts b/packages/utils/src/modules-sdk/internal-module-service-factory.ts new file mode 100644 index 0000000000..62b2039a20 --- /dev/null +++ b/packages/utils/src/modules-sdk/internal-module-service-factory.ts @@ -0,0 +1,442 @@ +import { + BaseFilterable, + Context, + FilterQuery, + FilterQuery as InternalFilterQuery, + FindConfig, + ModulesSdkTypes, +} from "@medusajs/types" +import { EntitySchema } from "@mikro-orm/core" +import { EntityClass } from "@mikro-orm/core/typings" +import { + doNotForceTransaction, + isDefined, + isObject, + isString, + lowerCaseFirst, + MedusaError, + shouldForceTransaction, +} from "../common" +import { buildQuery } from "./build-query" +import { + InjectManager, + InjectTransactionManager, + MedusaContext, +} from "./decorators" + +type SelectorAndData = { + selector: FilterQuery | BaseFilterable> + data: any +} + +export function internalModuleServiceFactory< + TContainer extends object = object +>( + model: any +): { + new ( + container: TContainer + ): ModulesSdkTypes.InternalModuleService +} { + const injectedRepositoryName = `${lowerCaseFirst(model.name)}Repository` + const propertyRepositoryName = `__${injectedRepositoryName}__` + + class AbstractService_ + implements ModulesSdkTypes.InternalModuleService + { + readonly __container__: TContainer; + [key: string]: any + + constructor(container: TContainer) { + this.__container__ = container + this[propertyRepositoryName] = container[injectedRepositoryName] + } + + static retrievePrimaryKeys(entity: EntityClass | EntitySchema) { + return ( + (entity as EntitySchema).meta?.primaryKeys ?? + (entity as EntityClass).prototype.__meta?.primaryKeys ?? ["id"] + ) + } + + static buildUniqueCompositeKeyValue(keys: string[], data: object) { + return keys.map((k) => data[k]).join("_") + } + + @InjectManager(propertyRepositoryName) + async retrieve( + idOrObject: string | object, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise { + const primaryKeys = AbstractService_.retrievePrimaryKeys(model) + + if ( + !isDefined(idOrObject) || + (isString(idOrObject) && primaryKeys.length > 1) || + ((!isString(idOrObject) || + (isObject(idOrObject) && !idOrObject[primaryKeys[0]])) && + primaryKeys.length === 1) + ) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `${ + primaryKeys.length === 1 + ? `${lowerCaseFirst(model.name) + " - " + primaryKeys[0]}` + : `${lowerCaseFirst(model.name)} - ${primaryKeys.join(", ")}` + } must be defined` + ) + } + + let primaryKeysCriteria = {} + if (primaryKeys.length === 1) { + primaryKeysCriteria[primaryKeys[0]] = idOrObject + } else { + const idOrObject_ = Array.isArray(idOrObject) + ? idOrObject + : [idOrObject] + primaryKeysCriteria = idOrObject_.map((primaryKeyValue) => ({ + $and: primaryKeys.map((key) => ({ [key]: primaryKeyValue[key] })), + })) + } + + const queryOptions = buildQuery(primaryKeysCriteria, config) + + const entities = await this[propertyRepositoryName].find( + queryOptions, + sharedContext + ) + + if (!entities?.length) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `${model.name} with ${primaryKeys.join(", ")}: ${ + Array.isArray(idOrObject) + ? idOrObject.map((v) => + [isString(v) ? v : Object.values(v)].join(", ") + ) + : idOrObject + } was not found` + ) + } + + return entities[0] + } + + @InjectManager(propertyRepositoryName) + async list( + filters: FilterQuery | BaseFilterable> = {}, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise { + const queryOptions = buildQuery(filters, config) + + return await this[propertyRepositoryName].find( + queryOptions, + sharedContext + ) + } + + @InjectManager(propertyRepositoryName) + async listAndCount( + filters: FilterQuery | BaseFilterable> = {}, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise<[TEntity[], number]> { + const queryOptions = buildQuery(filters, config) + + return await this[propertyRepositoryName].findAndCount( + queryOptions, + sharedContext + ) + } + + create(data: any, sharedContext?: Context): Promise + create(data: any[], sharedContext?: Context): Promise + + @InjectTransactionManager(shouldForceTransaction, propertyRepositoryName) + async create( + data: any | any[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + if (!isDefined(data) || (Array.isArray(data) && data.length === 0)) { + return (Array.isArray(data) ? [] : void 0) as TEntity | TEntity[] + } + + const data_ = Array.isArray(data) ? data : [data] + const entities = await this[propertyRepositoryName].create( + data_, + sharedContext + ) + + return Array.isArray(data) ? entities : entities[0] + } + + update(data: any[], sharedContext?: Context): Promise + update(data: any, sharedContext?: Context): Promise + update( + selectorAndData: SelectorAndData, + sharedContext?: Context + ): Promise + update( + selectorAndData: SelectorAndData[], + sharedContext?: Context + ): Promise + + @InjectTransactionManager(shouldForceTransaction, propertyRepositoryName) + async update( + input: any | any[] | SelectorAndData | SelectorAndData[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + if (!isDefined(input) || (Array.isArray(input) && input.length === 0)) { + return (Array.isArray(input) ? [] : void 0) as TEntity | TEntity[] + } + + const primaryKeys = AbstractService_.retrievePrimaryKeys(model) + const inputArray = Array.isArray(input) ? input : [input] + + const toUpdateData: { entity; update }[] = [] + + // Only used when we receive data and no selector + const keySelectorForDataOnly: any = { + $or: [], + } + const keySelectorDataMap = new Map() + + for (const input_ of inputArray) { + if (input_.selector) { + const entitiesToUpdate = await this.list( + input_.selector, + {}, + sharedContext + ) + // Create a pair of entity and data to update + entitiesToUpdate.forEach((entity) => { + toUpdateData.push({ + entity, + update: input_.data, + }) + }) + } else { + // in case we are manipulating the data, then extract the primary keys as a selector and the rest as the data to update + const selector = {} + + primaryKeys.forEach((key) => { + selector[key] = input_[key] + }) + + const uniqueCompositeKey = + AbstractService_.buildUniqueCompositeKeyValue(primaryKeys, input_) + keySelectorDataMap.set(uniqueCompositeKey, input_) + + keySelectorForDataOnly.$or.push(selector) + } + } + + if (keySelectorForDataOnly.$or.length) { + const entitiesToUpdate = await this.list( + keySelectorForDataOnly, + {}, + sharedContext + ) + + // Create a pair of entity and data to update + entitiesToUpdate.forEach((entity) => { + const uniqueCompositeKey = + AbstractService_.buildUniqueCompositeKeyValue(primaryKeys, entity) + toUpdateData.push({ + entity, + update: keySelectorDataMap.get(uniqueCompositeKey)!, + }) + }) + + // Only throw for missing entities when we dont have selectors involved as selector by design can return 0 entities + if (entitiesToUpdate.length !== keySelectorDataMap.size) { + const entityName = (model as EntityClass).name ?? model + + const compositeKeysValuesForFoundEntities = new Set( + entitiesToUpdate.map((entity) => { + return AbstractService_.buildUniqueCompositeKeyValue( + primaryKeys, + entity + ) + }) + ) + + const missingEntityValues: any[] = [] + + ;[...keySelectorDataMap.keys()].filter((key) => { + if (!compositeKeysValuesForFoundEntities.has(key)) { + const value = key.replace(/_/gi, " - ") + missingEntityValues.push(value) + } + }) + + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `${entityName} with ${primaryKeys.join( + ", " + )} "${missingEntityValues.join(", ")}" not found` + ) + } + } + + return await this[propertyRepositoryName].update( + toUpdateData, + sharedContext + ) + } + + delete(idOrSelector: string, sharedContext?: Context): Promise + delete(idOrSelector: string[], sharedContext?: Context): Promise + delete(idOrSelector: object, sharedContext?: Context): Promise + delete(idOrSelector: object[], sharedContext?: Context): Promise + delete( + idOrSelector: { + selector: FilterQuery | BaseFilterable> + }, + sharedContext?: Context + ): Promise + + @InjectTransactionManager(doNotForceTransaction, propertyRepositoryName) + async delete( + idOrSelector: + | string + | string[] + | object + | object[] + | { + selector: FilterQuery | BaseFilterable> + }, + @MedusaContext() sharedContext: Context = {} + ): Promise { + if ( + !isDefined(idOrSelector) || + (Array.isArray(idOrSelector) && idOrSelector.length === 0) + ) { + return + } + + const primaryKeys = AbstractService_.retrievePrimaryKeys(model) + + if ( + (Array.isArray(idOrSelector) && idOrSelector.length === 0) || + ((isString(idOrSelector) || + (Array.isArray(idOrSelector) && isString(idOrSelector[0]))) && + primaryKeys.length > 1) + ) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `${ + primaryKeys.length === 1 + ? `"${lowerCaseFirst(model.name) + " - " + primaryKeys[0]}"` + : `${lowerCaseFirst(model.name)} - ${primaryKeys.join(", ")}` + } must be defined` + ) + } + + const deleteCriteria: any = { + $or: [], + } + + if (isObject(idOrSelector) && "selector" in idOrSelector) { + const entitiesToDelete = await this.list( + idOrSelector.selector as FilterQuery, + { + select: primaryKeys, + }, + sharedContext + ) + + for (const entity of entitiesToDelete) { + const criteria = {} + primaryKeys.forEach((key) => { + criteria[key] = entity[key] + }) + deleteCriteria.$or.push(criteria) + } + } else { + const primaryKeysValues = Array.isArray(idOrSelector) + ? idOrSelector + : [idOrSelector] + + deleteCriteria.$or = primaryKeysValues.map((primaryKeyValue) => { + const criteria = {} + + if (isObject(primaryKeyValue)) { + Object.entries(primaryKeyValue).forEach(([key, value]) => { + criteria[key] = value + }) + } else { + criteria[primaryKeys[0]] = primaryKeyValue + } + + // TODO: Revisit + /*primaryKeys.forEach((key) => { + /!*if ( + isObject(primaryKeyValue) && + !isDefined(primaryKeyValue[key]) && + // primaryKeys.length > 1 + ) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `Composite key must contain all primary key fields: ${primaryKeys.join( + ", " + )}. Found: ${Object.keys(primaryKeyValue)}` + ) + }*!/ + + criteria[key] = isObject(primaryKeyValue) + ? primaryKeyValue[key] + : primaryKeyValue + })*/ + return criteria + }) + } + + await this[propertyRepositoryName].delete(deleteCriteria, sharedContext) + } + + @InjectTransactionManager(propertyRepositoryName) + async softDelete( + idsOrFilter: string[] | InternalFilterQuery, + @MedusaContext() sharedContext: Context = {} + ): Promise<[TEntity[], Record]> { + return await this[propertyRepositoryName].softDelete( + idsOrFilter, + sharedContext + ) + } + + @InjectTransactionManager(propertyRepositoryName) + async restore( + idsOrFilter: string[] | InternalFilterQuery, + @MedusaContext() sharedContext: Context = {} + ): Promise<[TEntity[], Record]> { + return await this[propertyRepositoryName].restore( + idsOrFilter, + sharedContext + ) + } + + upsert(data: any[], sharedContext?: Context): Promise + upsert(data: any, sharedContext?: Context): Promise + + @InjectTransactionManager(propertyRepositoryName) + async upsert( + data: any | any[], + @MedusaContext() sharedContext: Context = {} + ): Promise { + const data_ = Array.isArray(data) ? data : [data] + const entities = await this[propertyRepositoryName].upsert( + data_, + sharedContext + ) + return Array.isArray(data) ? entities : entities[0] + } + } + + return AbstractService_ as unknown as new ( + container: TContainer + ) => ModulesSdkTypes.InternalModuleService +} diff --git a/packages/utils/src/modules-sdk/loaders/container-loader-factory.ts b/packages/utils/src/modules-sdk/loaders/container-loader-factory.ts index 3d48981505..e89cca934a 100644 --- a/packages/utils/src/modules-sdk/loaders/container-loader-factory.ts +++ b/packages/utils/src/modules-sdk/loaders/container-loader-factory.ts @@ -8,7 +8,7 @@ import { } from "@medusajs/types" import { lowerCaseFirst } from "../../common" import { asClass } from "awilix" -import { abstractServiceFactory } from "../abstract-service-factory" +import { internalModuleServiceFactory } from "../internal-module-service-factory" import { mikroOrmBaseRepositoryFactory } from "../../dal" type RepositoryLoaderOptions = { @@ -96,7 +96,7 @@ export function loadModuleServices({ const finalService = moduleServicesMap.get(mappedServiceName) if (!finalService) { - moduleServicesMap.set(mappedServiceName, abstractServiceFactory(Model)) + moduleServicesMap.set(mappedServiceName, internalModuleServiceFactory(Model)) } }) diff --git a/packages/workflow-engine-inmemory/src/services/index.ts b/packages/workflow-engine-inmemory/src/services/index.ts index 5a6d313d86..75bcf7eb47 100644 --- a/packages/workflow-engine-inmemory/src/services/index.ts +++ b/packages/workflow-engine-inmemory/src/services/index.ts @@ -1,3 +1,2 @@ -export * from "./workflow-execution" export * from "./workflow-orchestrator" export * from "./workflows-module" diff --git a/packages/workflow-engine-inmemory/src/services/workflow-execution.ts b/packages/workflow-engine-inmemory/src/services/workflow-execution.ts deleted file mode 100644 index 158557ec0b..0000000000 --- a/packages/workflow-engine-inmemory/src/services/workflow-execution.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { WorkflowExecution } from "@models" - -type InjectedDependencies = { - workflowExecutionRepository: DAL.RepositoryService -} - -export class WorkflowExecutionService< - TEntity extends WorkflowExecution = WorkflowExecution -> extends ModulesSdkUtils.abstractServiceFactory( - WorkflowExecution -) { - protected workflowExecutionRepository_: DAL.RepositoryService - - constructor({ workflowExecutionRepository }: InjectedDependencies) { - // @ts-ignore - super(...arguments) - this.workflowExecutionRepository_ = workflowExecutionRepository - } -} diff --git a/packages/workflow-engine-inmemory/src/services/workflows-module.ts b/packages/workflow-engine-inmemory/src/services/workflows-module.ts index 31be5674d5..789fa57600 100644 --- a/packages/workflow-engine-inmemory/src/services/workflows-module.ts +++ b/packages/workflow-engine-inmemory/src/services/workflows-module.ts @@ -4,8 +4,8 @@ import { FindConfig, InternalModuleDeclaration, ModuleJoinerConfig, + ModulesSdkTypes, } from "@medusajs/types" -import {} from "@medusajs/types/src" import { InjectManager, InjectSharedContext, @@ -16,15 +16,12 @@ import type { UnwrapWorkflowInputDataType, WorkflowOrchestratorTypes, } from "@medusajs/workflows-sdk" -import { - WorkflowExecutionService, - WorkflowOrchestratorService, -} from "@services" +import { WorkflowOrchestratorService } from "@services" import { joinerConfig } from "../joiner-config" type InjectedDependencies = { baseRepository: DAL.RepositoryService - workflowExecutionService: WorkflowExecutionService + workflowExecutionService: ModulesSdkTypes.InternalModuleService workflowOrchestratorService: WorkflowOrchestratorService } @@ -32,7 +29,7 @@ export class WorkflowsModuleService implements WorkflowOrchestratorTypes.IWorkflowsModuleService { protected baseRepository_: DAL.RepositoryService - protected workflowExecutionService_: WorkflowExecutionService + protected workflowExecutionService_: ModulesSdkTypes.InternalModuleService protected workflowOrchestratorService_: WorkflowOrchestratorService constructor( @@ -64,7 +61,7 @@ export class WorkflowsModuleService sharedContext ) - return this.baseRepository_.serialize< + return await this.baseRepository_.serialize< WorkflowOrchestratorTypes.WorkflowExecutionDTO[] >(wfExecutions, { populate: true, diff --git a/packages/workflow-engine-inmemory/src/utils/workflow-orchestrator-storage.ts b/packages/workflow-engine-inmemory/src/utils/workflow-orchestrator-storage.ts index 7254f3b90d..60c9771def 100644 --- a/packages/workflow-engine-inmemory/src/utils/workflow-orchestrator-storage.ts +++ b/packages/workflow-engine-inmemory/src/utils/workflow-orchestrator-storage.ts @@ -5,14 +5,12 @@ import { TransactionStep, } from "@medusajs/orchestration" import { TransactionState } from "@medusajs/utils" -import { - WorkflowExecutionService, - WorkflowOrchestratorService, -} from "@services" +import { WorkflowOrchestratorService } from "@services" +import { ModulesSdkTypes } from "@medusajs/types" // eslint-disable-next-line max-len export class InMemoryDistributedTransactionStorage extends DistributedTransactionStorage { - private workflowExecutionService_: WorkflowExecutionService + private workflowExecutionService_: ModulesSdkTypes.InternalModuleService private workflowOrchestratorService_: WorkflowOrchestratorService private storage: Map = new Map() @@ -22,7 +20,7 @@ export class InMemoryDistributedTransactionStorage extends DistributedTransactio constructor({ workflowExecutionService, }: { - workflowExecutionService: WorkflowExecutionService + workflowExecutionService: ModulesSdkTypes.InternalModuleService }) { super() diff --git a/packages/workflow-engine-redis/src/services/index.ts b/packages/workflow-engine-redis/src/services/index.ts index 5a6d313d86..75bcf7eb47 100644 --- a/packages/workflow-engine-redis/src/services/index.ts +++ b/packages/workflow-engine-redis/src/services/index.ts @@ -1,3 +1,2 @@ -export * from "./workflow-execution" export * from "./workflow-orchestrator" export * from "./workflows-module" diff --git a/packages/workflow-engine-redis/src/services/workflow-execution.ts b/packages/workflow-engine-redis/src/services/workflow-execution.ts deleted file mode 100644 index 158557ec0b..0000000000 --- a/packages/workflow-engine-redis/src/services/workflow-execution.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" -import { WorkflowExecution } from "@models" - -type InjectedDependencies = { - workflowExecutionRepository: DAL.RepositoryService -} - -export class WorkflowExecutionService< - TEntity extends WorkflowExecution = WorkflowExecution -> extends ModulesSdkUtils.abstractServiceFactory( - WorkflowExecution -) { - protected workflowExecutionRepository_: DAL.RepositoryService - - constructor({ workflowExecutionRepository }: InjectedDependencies) { - // @ts-ignore - super(...arguments) - this.workflowExecutionRepository_ = workflowExecutionRepository - } -} diff --git a/packages/workflow-engine-redis/src/services/workflows-module.ts b/packages/workflow-engine-redis/src/services/workflows-module.ts index 31be5674d5..6667236626 100644 --- a/packages/workflow-engine-redis/src/services/workflows-module.ts +++ b/packages/workflow-engine-redis/src/services/workflows-module.ts @@ -4,8 +4,8 @@ import { FindConfig, InternalModuleDeclaration, ModuleJoinerConfig, + ModulesSdkTypes, } from "@medusajs/types" -import {} from "@medusajs/types/src" import { InjectManager, InjectSharedContext, @@ -16,15 +16,12 @@ import type { UnwrapWorkflowInputDataType, WorkflowOrchestratorTypes, } from "@medusajs/workflows-sdk" -import { - WorkflowExecutionService, - WorkflowOrchestratorService, -} from "@services" -import { joinerConfig } from "../joiner-config" +import {WorkflowOrchestratorService} from "@services" +import {joinerConfig} from "../joiner-config" type InjectedDependencies = { baseRepository: DAL.RepositoryService - workflowExecutionService: WorkflowExecutionService + workflowExecutionService: ModulesSdkTypes.InternalModuleService workflowOrchestratorService: WorkflowOrchestratorService } @@ -32,7 +29,7 @@ export class WorkflowsModuleService implements WorkflowOrchestratorTypes.IWorkflowsModuleService { protected baseRepository_: DAL.RepositoryService - protected workflowExecutionService_: WorkflowExecutionService + protected workflowExecutionService_: ModulesSdkTypes.InternalModuleService protected workflowOrchestratorService_: WorkflowOrchestratorService constructor( @@ -64,7 +61,7 @@ export class WorkflowsModuleService sharedContext ) - return this.baseRepository_.serialize< + return await this.baseRepository_.serialize< WorkflowOrchestratorTypes.WorkflowExecutionDTO[] >(wfExecutions, { populate: true, diff --git a/packages/workflow-engine-redis/src/utils/workflow-orchestrator-storage.ts b/packages/workflow-engine-redis/src/utils/workflow-orchestrator-storage.ts index 533181cf7f..512c8e7cf6 100644 --- a/packages/workflow-engine-redis/src/utils/workflow-orchestrator-storage.ts +++ b/packages/workflow-engine-redis/src/utils/workflow-orchestrator-storage.ts @@ -5,8 +5,8 @@ import { TransactionStep, } from "@medusajs/orchestration" import { TransactionState } from "@medusajs/utils" +import { ModulesSdkTypes } from "@medusajs/types" import { - WorkflowExecutionService, WorkflowOrchestratorService, } from "@services" import { Queue, Worker } from "bullmq" @@ -21,7 +21,7 @@ enum JobType { // eslint-disable-next-line max-len export class RedisDistributedTransactionStorage extends DistributedTransactionStorage { private static TTL_AFTER_COMPLETED = 60 * 15 // 15 minutes - private workflowExecutionService_: WorkflowExecutionService + private workflowExecutionService_: ModulesSdkTypes.InternalModuleService private workflowOrchestratorService_: WorkflowOrchestratorService private redisClient: Redis @@ -34,7 +34,7 @@ export class RedisDistributedTransactionStorage extends DistributedTransactionSt redisWorkerConnection, redisQueueName, }: { - workflowExecutionService: WorkflowExecutionService + workflowExecutionService: ModulesSdkTypes.InternalModuleService, redisConnection: Redis redisWorkerConnection: Redis redisQueueName: string