Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(utils): autogenerates create and update methods when dto is provided #6751

Merged
merged 11 commits into from
Mar 20, 2024
5 changes: 5 additions & 0 deletions .changeset/slow-plants-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@medusajs/utils": patch
---

feat(utils): autogenerates create and update methods when dto is provided
78 changes: 10 additions & 68 deletions packages/pricing/src/services/pricing-module.ts
Original file line number Diff line number Diff line change
@@ -94,13 +94,21 @@ export default class PricingModuleService<
InjectedDependencies,
PricingTypes.PriceSetDTO,
{
MoneyAmount: { dto: PricingTypes.MoneyAmountDTO }
MoneyAmount: {
dto: PricingTypes.MoneyAmountDTO
create_dto: PricingTypes.CreateMoneyAmountDTO
update_dto: PricingTypes.UpdateMoneyAmountDTO
}
PriceSetMoneyAmount: { dto: PricingTypes.PriceSetMoneyAmountDTO }
PriceSetMoneyAmountRules: {
dto: PricingTypes.PriceSetMoneyAmountRulesDTO
}
PriceRule: { dto: PricingTypes.PriceRuleDTO }
RuleType: { dto: PricingTypes.RuleTypeDTO }
RuleType: {
dto: PricingTypes.RuleTypeDTO
create_dto: PricingTypes.CreateRuleTypeDTO
update_dto: PricingTypes.UpdateRuleTypeDTO
}
PriceList: { dto: PricingTypes.PriceListDTO }
PriceListRule: { dto: PricingTypes.PriceListRuleDTO }
}
@@ -705,72 +713,6 @@ export default class PricingModuleService<
)
}

@InjectTransactionManager("baseRepository_")
async createMoneyAmounts(
data: PricingTypes.CreateMoneyAmountDTO[],
@MedusaContext() sharedContext: Context = {}
) {
const moneyAmounts = await this.moneyAmountService_.create(
data,
sharedContext
)

return await this.baseRepository_.serialize<PricingTypes.MoneyAmountDTO[]>(
moneyAmounts,
{
populate: true,
}
)
}

@InjectTransactionManager("baseRepository_")
async updateMoneyAmounts(
data: PricingTypes.UpdateMoneyAmountDTO[],
@MedusaContext() sharedContext: Context = {}
) {
const moneyAmounts = await this.moneyAmountService_.update(
data,
sharedContext
)

return await this.baseRepository_.serialize<PricingTypes.MoneyAmountDTO[]>(
moneyAmounts,
{
populate: true,
}
)
}

@InjectTransactionManager("baseRepository_")
async createRuleTypes(
data: PricingTypes.CreateRuleTypeDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<PricingTypes.RuleTypeDTO[]> {
const ruleTypes = await this.ruleTypeService_.create(data, sharedContext)

return await this.baseRepository_.serialize<PricingTypes.RuleTypeDTO[]>(
ruleTypes,
{
populate: true,
}
)
}

@InjectTransactionManager("baseRepository_")
async updateRuleTypes(
data: PricingTypes.UpdateRuleTypeDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<PricingTypes.RuleTypeDTO[]> {
const ruleTypes = await this.ruleTypeService_.update(data, sharedContext)

return await this.baseRepository_.serialize<PricingTypes.RuleTypeDTO[]>(
ruleTypes,
{
populate: true,
}
)
}

@InjectTransactionManager("baseRepository_")
async createPriceSetMoneyAmountRules(
data: PricingTypes.CreatePriceSetMoneyAmountRulesDTO[],
10 changes: 10 additions & 0 deletions packages/types/src/pricing/service.ts
Original file line number Diff line number Diff line change
@@ -1218,6 +1218,11 @@ export interface IPricingModuleService extends IModuleService {
sharedContext?: Context
): Promise<MoneyAmountDTO[]>

createMoneyAmounts(
data: CreateMoneyAmountDTO,
sharedContext?: Context
): Promise<MoneyAmountDTO>

/**
* This method updates existing money amounts.
*
@@ -1248,6 +1253,11 @@ export interface IPricingModuleService extends IModuleService {
sharedContext?: Context
): Promise<MoneyAmountDTO[]>

updateMoneyAmounts(
data: UpdateMoneyAmountDTO,
sharedContext?: Context
): Promise<MoneyAmountDTO>

/**
* This method deletes money amounts by their IDs.
*
157 changes: 122 additions & 35 deletions packages/utils/src/modules-sdk/abstract-module-service-factory.ts
Original file line number Diff line number Diff line change
@@ -33,21 +33,49 @@ type BaseMethods =
| "delete"
| "softDelete"
| "restore"
| "create"
| "update"

const readMethods = ["retrieve", "list", "listAndCount"] as BaseMethods[]
const writeMethods = ["delete", "softDelete", "restore"] as BaseMethods[]
const writeMethods = [
"delete",
"softDelete",
"restore",
"create",
"update",
] as BaseMethods[]

const methods: BaseMethods[] = [...readMethods, ...writeMethods]

type ModelsConfigTemplate = {
[ModelName: string]: { singular?: string; plural?: string; dto: object }
[ModelName: string]: {
singular?: string
plural?: string
dto: object
create_dto?: object
update_dto?: object
}
}

type ExtractSingularName<
T extends Record<any, any>,
K = keyof T
> = T[K] extends { singular?: string } ? T[K]["singular"] : K

type CreateMethodName<
ModelConfig extends Record<any, any>,
ModelKey = keyof ModelConfig
> = ModelConfig[ModelKey] extends { create_dto?: object }
? `create${ExtractPluralName<ModelConfig, ModelKey>}`
: never

type UpdateMethodName<
ModelConfig extends Record<any, any>,
ModelKey = keyof ModelConfig
> = ModelConfig[ModelKey] extends { update_dto?: object }
? `update${ExtractPluralName<ModelConfig, ModelKey>}`
: never

type ExtractPluralName<T extends Record<any, any>, K = keyof T> = T[K] extends {
plural?: string
}
@@ -100,53 +128,41 @@ export interface AbstractModuleServiceBase<TContainer, TMainModelDTO> {
export type AbstractModuleService<
TContainer,
TMainModelDTO,
TOtherModelNamesAndAssociatedDTO extends ModelsConfigTemplate
ModelsConfig extends ModelsConfigTemplate
> = AbstractModuleServiceBase<TContainer, TMainModelDTO> & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `retrieve${ExtractSingularName<
TOtherModelNamesAndAssociatedDTO,
K
> &
[K in keyof ModelsConfig as `retrieve${ExtractSingularName<ModelsConfig, K> &
string}`]: (
id: string,
config?: FindConfig<any>,
sharedContext?: Context
) => Promise<TOtherModelNamesAndAssociatedDTO[K & string]["dto"]>
) => Promise<ModelsConfig[K & string]["dto"]>
} & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `list${ExtractPluralName<
TOtherModelNamesAndAssociatedDTO,
K
> &
[K in keyof ModelsConfig as `list${ExtractPluralName<ModelsConfig, K> &
string}`]: (
filters?: any,
config?: FindConfig<any>,
sharedContext?: Context
) => Promise<TOtherModelNamesAndAssociatedDTO[K & string]["dto"][]>
) => Promise<ModelsConfig[K & string]["dto"][]>
} & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `listAndCount${ExtractPluralName<
TOtherModelNamesAndAssociatedDTO,
[K in keyof ModelsConfig as `listAndCount${ExtractPluralName<
ModelsConfig,
K
> &
string}`]: {
(filters?: any, config?: FindConfig<any>, sharedContext?: Context): Promise<
[TOtherModelNamesAndAssociatedDTO[K & string]["dto"][], number]
[ModelsConfig[K & string]["dto"][], number]
>
}
} & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `delete${ExtractPluralName<
TOtherModelNamesAndAssociatedDTO,
K
> &
[K in keyof ModelsConfig as `delete${ExtractPluralName<ModelsConfig, K> &
string}`]: {
(
primaryKeyValues: string | object | string[] | object[],
sharedContext?: Context
): Promise<void>
}
} & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `softDelete${ExtractPluralName<
TOtherModelNamesAndAssociatedDTO,
K
> &
[K in keyof ModelsConfig as `softDelete${ExtractPluralName<ModelsConfig, K> &
string}`]: {
<TReturnableLinkableKeys extends string>(
primaryKeyValues: string | object | string[] | object[],
@@ -155,17 +171,54 @@ export type AbstractModuleService<
): Promise<Record<string, string[]> | void>
}
} & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `restore${ExtractPluralName<
TOtherModelNamesAndAssociatedDTO,
K
> &
[K in keyof ModelsConfig as `restore${ExtractPluralName<ModelsConfig, K> &
string}`]: {
<TReturnableLinkableKeys extends string>(
primaryKeyValues: string | object | string[] | object[],
config?: RestoreReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
}
} & {
[ModelName in keyof ModelsConfig as CreateMethodName<
ModelsConfig,
ModelName
>]: {
(
data: ModelsConfig[ModelName]["create_dto"][],
sharedContext?: Context
): Promise<ModelsConfig[ModelName]["dto"][]>
}
} & {
[ModelName in keyof ModelsConfig as CreateMethodName<
ModelsConfig,
ModelName
>]: {
(
data: ModelsConfig[ModelName]["create_dto"],
sharedContext?: Context
): Promise<ModelsConfig[ModelName]["dto"]>
}
} & {
[ModelName in keyof ModelsConfig as UpdateMethodName<
ModelsConfig,
ModelName
>]: {
(
data: ModelsConfig[ModelName]["update_dto"][],
sharedContext?: Context
): Promise<ModelsConfig[ModelName]["dto"][]>
}
} & {
[ModelName in keyof ModelsConfig as UpdateMethodName<
ModelsConfig,
ModelName
>]: {
(
data: ModelsConfig[ModelName]["update_dto"],
sharedContext?: Context
): Promise<ModelsConfig[ModelName]["dto"]>
}
}

/**
@@ -211,7 +264,7 @@ export type AbstractModuleService<
export function abstractModuleServiceFactory<
TContainer,
TMainModelDTO,
TOtherModelNamesAndAssociatedDTO extends ModelsConfigTemplate
ModelsConfig extends ModelsConfigTemplate
>(
mainModel: Constructor<any>,
otherModels: ModelConfiguration[],
@@ -220,7 +273,7 @@ export function abstractModuleServiceFactory<
new (container: TContainer): AbstractModuleService<
TContainer,
TMainModelDTO,
TOtherModelNamesAndAssociatedDTO
ModelsConfig
>
} {
const buildMethodNamesFromModel = (
@@ -303,6 +356,44 @@ export function abstractModuleServiceFactory<

applyMethod(methodImplementation, 2)

break
case "create":
methodImplementation = async function <T extends object>(
this: AbstractModuleService_,
data = [],
sharedContext: Context = {}
): Promise<T | T[]> {
const serviceData = Array.isArray(data) ? data : [data]
const service = this.__container__[serviceRegistrationName]
const entities = await service.create(serviceData, sharedContext)
const response = Array.isArray(data) ? entities : entities[0]

return await this.baseRepository_.serialize<T | T[]>(response, {
populate: true,
})
}

applyMethod(methodImplementation, 1)

break
case "update":
methodImplementation = async function <T extends object>(
this: AbstractModuleService_,
data = [],
sharedContext: Context = {}
): Promise<T | T[]> {
const serviceData = Array.isArray(data) ? data : [data]
const service = this.__container__[serviceRegistrationName]
const entities = await service.update(serviceData, sharedContext)
const response = Array.isArray(data) ? entities : entities[0]

return await this.baseRepository_.serialize<T | T[]>(response, {
populate: true,
})
}

applyMethod(methodImplementation, 1)

break
case "list":
methodImplementation = async function <T extends object>(
@@ -532,9 +623,5 @@ export function abstractModuleServiceFactory<

return AbstractModuleService_ as unknown as new (
container: TContainer
) => AbstractModuleService<
TContainer,
TMainModelDTO,
TOtherModelNamesAndAssociatedDTO
>
) => AbstractModuleService<TContainer, TMainModelDTO, ModelsConfig>
}