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