Merge branch 'develop' into feat/payment-module-models
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
Context,
|
||||
DAL,
|
||||
FilterQuery as InternalFilerQuery,
|
||||
FilterQuery as InternalFilterQuery,
|
||||
RepositoryTransformOptions,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
@@ -16,9 +16,9 @@ import {
|
||||
EntityName,
|
||||
FilterQuery as MikroFilterQuery,
|
||||
} from "@mikro-orm/core/typings"
|
||||
import { isString, MedusaError } from "../../common"
|
||||
import { MedusaError, isString } from "../../common"
|
||||
import { MedusaContext } from "../../decorators"
|
||||
import { buildQuery, InjectTransactionManager } from "../../modules-sdk"
|
||||
import { InjectTransactionManager, buildQuery } from "../../modules-sdk"
|
||||
import {
|
||||
getSoftDeletedCascadedEntitiesIdsMappedBy,
|
||||
transactionWrapper,
|
||||
@@ -106,7 +106,7 @@ export class MikroOrmBaseRepository<
|
||||
|
||||
@InjectTransactionManager()
|
||||
async softDelete(
|
||||
idsOrFilter: string[] | InternalFilerQuery,
|
||||
idsOrFilter: string[] | InternalFilterQuery,
|
||||
@MedusaContext()
|
||||
{ transactionManager: manager }: Context = {}
|
||||
): Promise<[T[], Record<string, unknown[]>]> {
|
||||
@@ -138,7 +138,7 @@ export class MikroOrmBaseRepository<
|
||||
|
||||
@InjectTransactionManager()
|
||||
async restore(
|
||||
idsOrFilter: string[] | InternalFilerQuery,
|
||||
idsOrFilter: string[] | InternalFilterQuery,
|
||||
@MedusaContext()
|
||||
{ transactionManager: manager }: Context = {}
|
||||
): Promise<[T[], Record<string, unknown[]>]> {
|
||||
@@ -224,7 +224,7 @@ type DtoBasedMutationMethods = "create" | "update"
|
||||
|
||||
export function mikroOrmBaseRepositoryFactory<
|
||||
T extends object = object,
|
||||
TDTos extends { [K in DtoBasedMutationMethods]?: any } = {
|
||||
TDTOs extends { [K in DtoBasedMutationMethods]?: any } = {
|
||||
[K in DtoBasedMutationMethods]?: any
|
||||
}
|
||||
>(entity: EntityClass<T> | EntitySchema<T>) {
|
||||
@@ -242,11 +242,11 @@ export function mikroOrmBaseRepositoryFactory<
|
||||
static retrievePrimaryKeys(entity: EntityClass<T> | EntitySchema<T>) {
|
||||
return (
|
||||
(entity as EntitySchema<T>).meta?.primaryKeys ??
|
||||
(entity as EntityClass<T>).prototype.__meta.primaryKeys
|
||||
(entity as EntityClass<T>).prototype.__meta.primaryKeys ?? ["id"]
|
||||
)
|
||||
}
|
||||
|
||||
async create(data: TDTos["create"][], context?: Context): Promise<T[]> {
|
||||
async create(data: TDTOs["create"][], context?: Context): Promise<T[]> {
|
||||
const manager = this.getActiveManager<EntityManager>(context)
|
||||
|
||||
const entities = data.map((data_) => {
|
||||
@@ -261,7 +261,8 @@ export function mikroOrmBaseRepositoryFactory<
|
||||
return entities
|
||||
}
|
||||
|
||||
async update(data: TDTos["update"][], context?: Context): Promise<T[]> {
|
||||
async update(data: TDTOs["update"][], context?: Context): Promise<T[]> {
|
||||
// TODO: Move this logic to the service packages/utils/src/modules-sdk/abstract-service-factory.ts
|
||||
const manager = this.getActiveManager<EntityManager>(context)
|
||||
|
||||
const primaryKeys =
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
import {
|
||||
Context,
|
||||
FilterQuery as InternalFilterQuery,
|
||||
FindConfig,
|
||||
} from "@medusajs/types"
|
||||
import { EntitySchema } from "@mikro-orm/core"
|
||||
import { EntityClass } from "@mikro-orm/core/typings"
|
||||
import {
|
||||
doNotForceTransaction,
|
||||
isDefined,
|
||||
isString,
|
||||
lowerCaseFirst,
|
||||
MedusaError,
|
||||
shouldForceTransaction,
|
||||
upperCaseFirst,
|
||||
} from "../common"
|
||||
import { MedusaContext } from "../decorators"
|
||||
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<TEntityMethod = TEntity>(
|
||||
id: string,
|
||||
config?: FindConfig<TEntityMethod>,
|
||||
sharedContext?: Context
|
||||
): Promise<TEntity>
|
||||
list<TEntityMethod = TEntity>(
|
||||
filters?: TFilters["list"],
|
||||
config?: FindConfig<TEntityMethod>,
|
||||
sharedContext?: Context
|
||||
): Promise<TEntity[]>
|
||||
listAndCount<TEntityMethod = TEntity>(
|
||||
filters?: TFilters["listAndCount"],
|
||||
config?: FindConfig<TEntityMethod>,
|
||||
sharedContext?: Context
|
||||
): Promise<[TEntity[], number]>
|
||||
create(data: TDTOs["create"][], sharedContext?: Context): Promise<TEntity[]>
|
||||
update(data: TDTOs["update"][], sharedContext?: Context): Promise<TEntity[]>
|
||||
delete(
|
||||
primaryKeyValues: string[] | object[],
|
||||
sharedContext?: Context
|
||||
): Promise<void>
|
||||
softDelete(
|
||||
idsOrFilter: string[] | InternalFilterQuery,
|
||||
sharedContext?: Context
|
||||
): Promise<[TEntity[], Record<string, unknown[]>]>
|
||||
restore(
|
||||
idsOrFilter: string[] | InternalFilterQuery,
|
||||
sharedContext?: Context
|
||||
): Promise<[TEntity[], Record<string, unknown[]>]>
|
||||
}
|
||||
|
||||
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 <TEntity extends {}>(container: TContainer): AbstractService<
|
||||
TEntity,
|
||||
TContainer,
|
||||
TDTOs,
|
||||
TFilters
|
||||
>
|
||||
} {
|
||||
const injectedRepositoryName = `${lowerCaseFirst(model.name)}Repository`
|
||||
const propertyRepositoryName = `__${injectedRepositoryName}__`
|
||||
|
||||
class AbstractService_<TEntity extends {}>
|
||||
implements AbstractService<TEntity, TContainer, TDTOs, TFilters>
|
||||
{
|
||||
readonly __container__: TContainer;
|
||||
[key: string]: any
|
||||
|
||||
constructor(container: TContainer) {
|
||||
this.__container__ = container
|
||||
this[propertyRepositoryName] = container[injectedRepositoryName]
|
||||
}
|
||||
|
||||
static retrievePrimaryKeys(entity: EntityClass<any> | EntitySchema<any>) {
|
||||
return (
|
||||
(entity as EntitySchema<any>).meta?.primaryKeys ??
|
||||
(entity as EntityClass<any>).prototype.__meta?.primaryKeys ?? ["id"]
|
||||
)
|
||||
}
|
||||
|
||||
@InjectManager(propertyRepositoryName)
|
||||
async retrieve<TEntityMethod = TEntity>(
|
||||
primaryKeyValues: string | string[] | object[],
|
||||
config: FindConfig<TEntityMethod> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity> {
|
||||
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<TEntity>(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<TEntityMethod = TEntity>(
|
||||
filters: TFilters["list"] = {},
|
||||
config: FindConfig<TEntityMethod> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity[]> {
|
||||
const queryOptions = buildQuery<TEntity>(filters, config)
|
||||
|
||||
return (await this[propertyRepositoryName].find(
|
||||
queryOptions,
|
||||
sharedContext
|
||||
)) as TEntity[]
|
||||
}
|
||||
|
||||
@InjectManager(propertyRepositoryName)
|
||||
async listAndCount<TEntityMethod = TEntity>(
|
||||
filters: TFilters["listAndCount"] = {},
|
||||
config: FindConfig<TEntityMethod> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<[TEntity[], number]> {
|
||||
const queryOptions = buildQuery<TEntity>(filters, config)
|
||||
|
||||
return (await this[propertyRepositoryName].findAndCount(
|
||||
queryOptions,
|
||||
sharedContext
|
||||
)) as [TEntity[], number]
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, propertyRepositoryName)
|
||||
async create(
|
||||
data: TDTOs["create"][],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity[]> {
|
||||
return (await this[propertyRepositoryName].create(
|
||||
data,
|
||||
sharedContext
|
||||
)) as TEntity[]
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, propertyRepositoryName)
|
||||
async update(
|
||||
data: TDTOs["update"][],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity[]> {
|
||||
return (await this[propertyRepositoryName].update(
|
||||
data,
|
||||
sharedContext
|
||||
)) as TEntity[]
|
||||
}
|
||||
|
||||
@InjectTransactionManager(doNotForceTransaction, propertyRepositoryName)
|
||||
async delete(
|
||||
primaryKeyValues: string[] | object[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<void> {
|
||||
await this[propertyRepositoryName].delete(primaryKeyValues, sharedContext)
|
||||
}
|
||||
|
||||
@InjectTransactionManager(propertyRepositoryName)
|
||||
async softDelete(
|
||||
idsOrFilter: string[] | InternalFilterQuery,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<[TEntity[], Record<string, unknown[]>]> {
|
||||
return await this[propertyRepositoryName].softDelete(
|
||||
idsOrFilter,
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
|
||||
@InjectTransactionManager(propertyRepositoryName)
|
||||
async restore(
|
||||
idsOrFilter: string[] | InternalFilterQuery,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<[TEntity[], Record<string, unknown[]>]> {
|
||||
return await this[propertyRepositoryName].restore(
|
||||
idsOrFilter,
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return AbstractService_ as unknown as new <TEntity extends {}>(
|
||||
container: TContainer
|
||||
) => AbstractService<TEntity, TContainer, TDTOs, TFilters>
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
export * from "./load-module-database-config"
|
||||
export * from "./decorators"
|
||||
export * from "./build-query"
|
||||
export * from "./retrieve-entity"
|
||||
export * from "./loaders/mikro-orm-connection-loader"
|
||||
export * from "./create-pg-connection"
|
||||
export * from "./migration-scripts"
|
||||
export * from "./abstract-service-factory"
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import { Context, DAL, FindConfig } from "@medusajs/types"
|
||||
import {
|
||||
MedusaError,
|
||||
isDefined,
|
||||
lowerCaseFirst,
|
||||
upperCaseFirst,
|
||||
} from "../common"
|
||||
import { buildQuery } from "./build-query"
|
||||
|
||||
type RetrieveEntityParams<TDTO> = {
|
||||
id: string
|
||||
identifierColumn?: string
|
||||
entityName: string
|
||||
repository: DAL.TreeRepositoryService | DAL.RepositoryService
|
||||
config: FindConfig<TDTO>
|
||||
sharedContext?: Context
|
||||
}
|
||||
|
||||
export async function retrieveEntity<TEntity, TDTO>({
|
||||
id,
|
||||
identifierColumn = "id",
|
||||
entityName,
|
||||
repository,
|
||||
config = {},
|
||||
sharedContext,
|
||||
}: RetrieveEntityParams<TDTO>): Promise<TEntity> {
|
||||
if (!isDefined(id)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`"${lowerCaseFirst(entityName)}${upperCaseFirst(
|
||||
identifierColumn
|
||||
)}" must be defined`
|
||||
)
|
||||
}
|
||||
|
||||
const queryOptions = buildQuery<TEntity>(
|
||||
{
|
||||
[identifierColumn]: id,
|
||||
},
|
||||
config
|
||||
)
|
||||
|
||||
const entities = await repository.find(queryOptions, sharedContext)
|
||||
|
||||
if (!entities?.length) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`${entityName} with ${identifierColumn}: ${id} was not found`
|
||||
)
|
||||
}
|
||||
|
||||
return entities[0]
|
||||
}
|
||||
@@ -33,3 +33,11 @@ export enum CampaignBudgetType {
|
||||
SPEND = "spend",
|
||||
USAGE = "usage",
|
||||
}
|
||||
|
||||
export enum ComputedActions {
|
||||
ADD_ITEM_ADJUSTMENT = "addItemAdjustment",
|
||||
ADD_SHIPPING_METHOD_ADJUSTMENT = "addShippingMethodAdjustment",
|
||||
REMOVE_ITEM_ADJUSTMENT = "removeItemAdjustment",
|
||||
REMOVE_SHIPPING_METHOD_ADJUSTMENT = "removeShippingMethodAdjustment",
|
||||
CAMPAIGN_BUDGET_EXCEEDED = "campaignBudgetExceeded",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user