Merge branch 'develop' into feat/payment-module-models

This commit is contained in:
Frane Polić
2024-01-18 14:19:18 +01:00
committed by GitHub
443 changed files with 18487 additions and 8150 deletions
@@ -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 -1
View File
@@ -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]
}
+8
View File
@@ -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",
}