chore: Abstract module services (#6087)

**What**
Create a service abstraction for the modules internal service layer. The objective is to reduce the effort of building new modules when the logic is the same or otherwise allow to override the default behavior.

Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2024-01-18 10:20:08 +01:00
committed by GitHub
parent 80feb972cb
commit 130c641e5c
46 changed files with 857 additions and 2836 deletions

View File

@@ -2,32 +2,16 @@ import { DALUtils } from "@medusajs/utils"
import { AuthProvider } from "@models"
import { RepositoryTypes } from "@types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { Context } from "@medusajs/types"
export class AuthProviderRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
AuthProvider,
{
create: RepositoryTypes.CreateAuthProviderDTO
update: RepositoryTypes.UpdateAuthProviderDTO
}
>(AuthProvider) {
constructor(...args: any[]) {
// @ts-ignore
super(...arguments)
}
async update(
data: RepositoryTypes.UpdateAuthProviderDTO[],
context: Context = {}
): Promise<AuthProvider[]> {
const manager = this.getActiveManager<SqlEntityManager>(context)
const authProviders = data.map(({ provider, update }) => {
return manager.assign(provider, update)
})
manager.persist(authProviders)
return authProviders
}
}

View File

@@ -1,45 +1,17 @@
import { Context } from "@medusajs/types"
import { DALUtils } from "@medusajs/utils"
import { AuthUser } from "@models"
import { RepositoryTypes } from "@types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
export class AuthUserRepository extends DALUtils.mikroOrmBaseRepositoryFactory(
AuthUser
) {
export class AuthUserRepository extends DALUtils.mikroOrmBaseRepositoryFactory<
AuthUser,
{
create: RepositoryTypes.CreateAuthUserDTO
update: RepositoryTypes.UpdateAuthUserDTO
}
>(AuthUser) {
constructor(...args: any[]) {
// @ts-ignore
super(...arguments)
}
async create(
data: RepositoryTypes.CreateAuthUserDTO[],
context: Context = {}
): Promise<AuthUser[]> {
const toCreate = data.map((authUser) => {
const authUserClone = { ...authUser } as any
authUserClone.provider ??= authUser.provider_id
return authUserClone
})
return await super.create(toCreate, context)
}
async update(
data: RepositoryTypes.UpdateAuthUserDTO[],
context: Context = {}
): Promise<AuthUser[]> {
const manager = this.getActiveManager<SqlEntityManager>(context)
const authUsers = data.map(({ user, update }) => {
return manager.assign(user, update)
})
manager.persist(authUsers)
return authUsers
}
}

View File

@@ -1,16 +1,8 @@
import { Context, DAL, FindConfig } from "@medusajs/types"
import {
InjectManager,
InjectTransactionManager,
MedusaContext,
MedusaError,
ModulesSdkUtils,
retrieveEntity,
} from "@medusajs/utils"
import { DAL } from "@medusajs/types"
import { ModulesSdkUtils } from "@medusajs/utils"
import { AuthProvider } from "@models"
import { AuthProviderRepository } from "@repositories"
import { RepositoryTypes, ServiceTypes } from "@types"
import { ServiceTypes } from "@types"
type InjectedDependencies = {
authProviderRepository: DAL.RepositoryService
@@ -18,122 +10,15 @@ type InjectedDependencies = {
export default class AuthProviderService<
TEntity extends AuthProvider = AuthProvider
> {
protected readonly authProviderRepository_: DAL.RepositoryService
constructor({ authProviderRepository }: InjectedDependencies) {
this.authProviderRepository_ = authProviderRepository
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ServiceTypes.CreateAuthProviderDTO
update: ServiceTypes.UpdateAuthProviderDTO
}
@InjectManager("authProviderRepository_")
async retrieve(
provider: string,
config: FindConfig<ServiceTypes.AuthProviderDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
return (await retrieveEntity<AuthProvider, ServiceTypes.AuthProviderDTO>({
id: provider,
identifierColumn: "provider",
entityName: AuthProvider.name,
repository: this.authProviderRepository_,
config,
sharedContext,
})) as TEntity
}
@InjectManager("authProviderRepository_")
async list(
filters: ServiceTypes.FilterableAuthProviderProps = {},
config: FindConfig<ServiceTypes.AuthProviderDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
const queryConfig = ModulesSdkUtils.buildQuery<AuthProvider>(
filters,
config
)
return (await this.authProviderRepository_.find(
queryConfig,
sharedContext
)) as TEntity[]
}
@InjectManager("authProviderRepository_")
async listAndCount(
filters: ServiceTypes.FilterableAuthProviderProps = {},
config: FindConfig<ServiceTypes.AuthProviderDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
const queryConfig = ModulesSdkUtils.buildQuery<AuthProvider>(
filters,
config
)
return (await this.authProviderRepository_.findAndCount(
queryConfig,
sharedContext
)) as [TEntity[], number]
}
@InjectTransactionManager("authProviderRepository_")
async create(
data: ServiceTypes.CreateAuthProviderDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (
this.authProviderRepository_ as AuthProviderRepository
).create(data, sharedContext)) as TEntity[]
}
@InjectTransactionManager("authProviderRepository_")
async update(
data: ServiceTypes.UpdateAuthProviderDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
const authProviderIds = data.map(
(authProviderData) => authProviderData.provider
)
const existingAuthProviders = await this.list(
{
provider: authProviderIds,
},
{},
sharedContext
)
const updates: RepositoryTypes.UpdateAuthProviderDTO[] = []
const existingAuthProvidersMap = new Map(
existingAuthProviders.map<[string, AuthProvider]>((authProvider) => [
authProvider.provider,
authProvider,
])
)
for (const update of data) {
const provider = existingAuthProvidersMap.get(update.provider)
if (!provider) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`AuthProvider with provider "${update.provider}" not found`
)
}
updates.push({ update, provider })
}
return (await (
this.authProviderRepository_ as AuthProviderRepository
).update(updates, sharedContext)) as TEntity[]
}
@InjectTransactionManager("authProviderRepository_")
async delete(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.authProviderRepository_.delete(ids, sharedContext)
>(AuthProvider)<TEntity> {
constructor(container: InjectedDependencies) {
// @ts-ignore
super(...arguments)
}
}

View File

@@ -1,126 +1,23 @@
import { Context, DAL, FindConfig } from "@medusajs/types"
import {
InjectManager,
InjectTransactionManager,
MedusaContext,
MedusaError,
ModulesSdkUtils,
retrieveEntity,
} from "@medusajs/utils"
import { DAL } from "@medusajs/types"
import { ModulesSdkUtils } from "@medusajs/utils"
import { AuthUser } from "@models"
import { AuthUserRepository } from "@repositories"
import { RepositoryTypes, ServiceTypes } from "@types"
import { ServiceTypes } from "@types"
type InjectedDependencies = {
authUserRepository: DAL.RepositoryService
}
export default class AuthUserService<TEntity extends AuthUser = AuthUser> {
protected readonly authUserRepository_: DAL.RepositoryService
export default class AuthUserService<
TEntity extends AuthUser = AuthUser
> extends ModulesSdkUtils.abstractServiceFactory<
InjectedDependencies,
{
create: ServiceTypes.CreateAuthUserDTO
}
>(AuthUser)<TEntity> {
constructor({ authUserRepository }: InjectedDependencies) {
this.authUserRepository_ = authUserRepository
}
@InjectManager("authUserRepository_")
async retrieve(
provider: string,
config: FindConfig<ServiceTypes.AuthUserDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity> {
return (await retrieveEntity<AuthUser, ServiceTypes.AuthUserDTO>({
id: provider,
entityName: AuthUser.name,
repository: this.authUserRepository_,
config,
sharedContext,
})) as TEntity
}
@InjectManager("authUserRepository_")
async list(
filters: ServiceTypes.FilterableAuthProviderProps = {},
config: FindConfig<ServiceTypes.AuthUserDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
const queryConfig = ModulesSdkUtils.buildQuery<AuthUser>(filters, config)
return (await this.authUserRepository_.find(
queryConfig,
sharedContext
)) as TEntity[]
}
@InjectManager("authUserRepository_")
async listAndCount(
filters: ServiceTypes.FilterableAuthUserProps = {},
config: FindConfig<ServiceTypes.AuthUserDTO> = {},
@MedusaContext() sharedContext: Context = {}
): Promise<[TEntity[], number]> {
const queryConfig = ModulesSdkUtils.buildQuery<AuthUser>(filters, config)
return (await this.authUserRepository_.findAndCount(
queryConfig,
sharedContext
)) as [TEntity[], number]
}
@InjectTransactionManager("authUserRepository_")
async create(
data: ServiceTypes.CreateAuthUserDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
return (await (this.authUserRepository_ as AuthUserRepository).create(
data,
sharedContext
)) as TEntity[]
}
@InjectTransactionManager("authUserRepository_")
async update(
data: ServiceTypes.UpdateAuthUserDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TEntity[]> {
const existingUsers = await this.list(
{ id: data.map(({ id }) => id) },
{},
sharedContext
)
const existingUsersMap = new Map(
existingUsers.map<[string, AuthUser]>((authUser) => [
authUser.id,
authUser,
])
)
const updates: RepositoryTypes.UpdateAuthUserDTO[] = []
for (const update of data) {
const user = existingUsersMap.get(update.id)
if (!user) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`AuthUser with id "${update.id}" not found`
)
}
updates.push({ update, user })
}
return (await (this.authUserRepository_ as AuthUserRepository).update(
updates,
sharedContext
)) as TEntity[]
}
@InjectTransactionManager("authUserRepository_")
async delete(
ids: string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await this.authUserRepository_.delete(ids, sharedContext)
// @ts-ignore
super(...arguments)
}
}