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

what:

when you provide an optional create_dto or update_dto to the model factory types, the abstract service will generate a simple service method for the public services of the modules.

```
MoneyAmount: {
  dto: PricingTypes.MoneyAmountDTO
  create_dto: PricingTypes.CreateMoneyAmountDTO
}
```

In the above example, only a create method will be generated, but the update will be skipped.
This commit is contained in:
Riqwan Thamir
2024-03-20 14:33:24 +00:00
committed by GitHub
parent 64c2731e46
commit 4974f5e455
4 changed files with 146 additions and 104 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/utils": patch
---
feat(utils): autogenerates create and update methods when dto is provided
+10 -68
View File
@@ -94,13 +94,21 @@ export default class PricingModuleService<
InjectedDependencies, InjectedDependencies,
PricingTypes.PriceSetDTO, PricingTypes.PriceSetDTO,
{ {
MoneyAmount: { dto: PricingTypes.MoneyAmountDTO } MoneyAmount: {
dto: PricingTypes.MoneyAmountDTO
create: PricingTypes.CreateMoneyAmountDTO
update: PricingTypes.UpdateMoneyAmountDTO
}
PriceSetMoneyAmount: { dto: PricingTypes.PriceSetMoneyAmountDTO } PriceSetMoneyAmount: { dto: PricingTypes.PriceSetMoneyAmountDTO }
PriceSetMoneyAmountRules: { PriceSetMoneyAmountRules: {
dto: PricingTypes.PriceSetMoneyAmountRulesDTO dto: PricingTypes.PriceSetMoneyAmountRulesDTO
} }
PriceRule: { dto: PricingTypes.PriceRuleDTO } PriceRule: { dto: PricingTypes.PriceRuleDTO }
RuleType: { dto: PricingTypes.RuleTypeDTO } RuleType: {
dto: PricingTypes.RuleTypeDTO
create: PricingTypes.CreateRuleTypeDTO
update: PricingTypes.UpdateRuleTypeDTO
}
PriceList: { dto: PricingTypes.PriceListDTO } PriceList: { dto: PricingTypes.PriceListDTO }
PriceListRule: { dto: PricingTypes.PriceListRuleDTO } 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_") @InjectTransactionManager("baseRepository_")
async createPriceSetMoneyAmountRules( async createPriceSetMoneyAmountRules(
data: PricingTypes.CreatePriceSetMoneyAmountRulesDTO[], data: PricingTypes.CreatePriceSetMoneyAmountRulesDTO[],
+10
View File
@@ -1218,6 +1218,11 @@ export interface IPricingModuleService extends IModuleService {
sharedContext?: Context sharedContext?: Context
): Promise<MoneyAmountDTO[]> ): Promise<MoneyAmountDTO[]>
createMoneyAmounts(
data: CreateMoneyAmountDTO,
sharedContext?: Context
): Promise<MoneyAmountDTO>
/** /**
* This method updates existing money amounts. * This method updates existing money amounts.
* *
@@ -1248,6 +1253,11 @@ export interface IPricingModuleService extends IModuleService {
sharedContext?: Context sharedContext?: Context
): Promise<MoneyAmountDTO[]> ): Promise<MoneyAmountDTO[]>
updateMoneyAmounts(
data: UpdateMoneyAmountDTO,
sharedContext?: Context
): Promise<MoneyAmountDTO>
/** /**
* This method deletes money amounts by their IDs. * This method deletes money amounts by their IDs.
* *
@@ -12,11 +12,11 @@ import {
SoftDeleteReturn, SoftDeleteReturn,
} from "@medusajs/types" } from "@medusajs/types"
import { import {
MapToConfig,
isString, isString,
kebabCase, kebabCase,
lowerCaseFirst, lowerCaseFirst,
mapObjectTo, mapObjectTo,
MapToConfig,
pluralize, pluralize,
upperCaseFirst, upperCaseFirst,
} from "../common" } from "../common"
@@ -33,14 +33,28 @@ type BaseMethods =
| "delete" | "delete"
| "softDelete" | "softDelete"
| "restore" | "restore"
| "create"
| "update"
const readMethods = ["retrieve", "list", "listAndCount"] as BaseMethods[] 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] const methods: BaseMethods[] = [...readMethods, ...writeMethods]
type ModelsConfigTemplate = { type ModelsConfigTemplate = {
[ModelName: string]: { singular?: string; plural?: string; dto: object } [ModelName: string]: {
singular?: string
plural?: string
dto: object
create?: object
update?: object
}
} }
type ExtractSingularName< type ExtractSingularName<
@@ -48,6 +62,20 @@ type ExtractSingularName<
K = keyof T K = keyof T
> = T[K] extends { singular?: string } ? T[K]["singular"] : K > = T[K] extends { singular?: string } ? T[K]["singular"] : K
type CreateMethodName<
ModelConfig extends Record<any, any>,
ModelKey = keyof ModelConfig
> = ModelConfig[ModelKey] extends { create?: object }
? `create${ExtractPluralName<ModelConfig, ModelKey>}`
: never
type UpdateMethodName<
ModelConfig extends Record<any, any>,
ModelKey = keyof ModelConfig
> = ModelConfig[ModelKey] extends { update?: object }
? `update${ExtractPluralName<ModelConfig, ModelKey>}`
: never
type ExtractPluralName<T extends Record<any, any>, K = keyof T> = T[K] extends { type ExtractPluralName<T extends Record<any, any>, K = keyof T> = T[K] extends {
plural?: string plural?: string
} }
@@ -100,42 +128,33 @@ export interface AbstractModuleServiceBase<TContainer, TMainModelDTO> {
export type AbstractModuleService< export type AbstractModuleService<
TContainer, TContainer,
TMainModelDTO, TMainModelDTO,
TOtherModelNamesAndAssociatedDTO extends ModelsConfigTemplate ModelsConfig extends ModelsConfigTemplate
> = AbstractModuleServiceBase<TContainer, TMainModelDTO> & { > = AbstractModuleServiceBase<TContainer, TMainModelDTO> & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `retrieve${ExtractSingularName< [K in keyof ModelsConfig as `retrieve${ExtractSingularName<ModelsConfig, K> &
TOtherModelNamesAndAssociatedDTO,
K
> &
string}`]: ( string}`]: (
id: string, id: string,
config?: FindConfig<any>, config?: FindConfig<any>,
sharedContext?: Context sharedContext?: Context
) => Promise<TOtherModelNamesAndAssociatedDTO[K & string]["dto"]> ) => Promise<ModelsConfig[K & string]["dto"]>
} & { } & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `list${ExtractPluralName< [K in keyof ModelsConfig as `list${ExtractPluralName<ModelsConfig, K> &
TOtherModelNamesAndAssociatedDTO,
K
> &
string}`]: ( string}`]: (
filters?: any, filters?: any,
config?: FindConfig<any>, config?: FindConfig<any>,
sharedContext?: Context sharedContext?: Context
) => Promise<TOtherModelNamesAndAssociatedDTO[K & string]["dto"][]> ) => Promise<ModelsConfig[K & string]["dto"][]>
} & { } & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `listAndCount${ExtractPluralName< [K in keyof ModelsConfig as `listAndCount${ExtractPluralName<
TOtherModelNamesAndAssociatedDTO, ModelsConfig,
K K
> & > &
string}`]: { string}`]: {
(filters?: any, config?: FindConfig<any>, sharedContext?: Context): Promise< (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< [K in keyof ModelsConfig as `delete${ExtractPluralName<ModelsConfig, K> &
TOtherModelNamesAndAssociatedDTO,
K
> &
string}`]: { string}`]: {
( (
primaryKeyValues: string | object | string[] | object[], primaryKeyValues: string | object | string[] | object[],
@@ -143,10 +162,7 @@ export type AbstractModuleService<
): Promise<void> ): Promise<void>
} }
} & { } & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `softDelete${ExtractPluralName< [K in keyof ModelsConfig as `softDelete${ExtractPluralName<ModelsConfig, K> &
TOtherModelNamesAndAssociatedDTO,
K
> &
string}`]: { string}`]: {
<TReturnableLinkableKeys extends string>( <TReturnableLinkableKeys extends string>(
primaryKeyValues: string | object | string[] | object[], primaryKeyValues: string | object | string[] | object[],
@@ -155,10 +171,7 @@ export type AbstractModuleService<
): Promise<Record<string, string[]> | void> ): Promise<Record<string, string[]> | void>
} }
} & { } & {
[K in keyof TOtherModelNamesAndAssociatedDTO as `restore${ExtractPluralName< [K in keyof ModelsConfig as `restore${ExtractPluralName<ModelsConfig, K> &
TOtherModelNamesAndAssociatedDTO,
K
> &
string}`]: { string}`]: {
<TReturnableLinkableKeys extends string>( <TReturnableLinkableKeys extends string>(
primaryKeyValues: string | object | string[] | object[], primaryKeyValues: string | object | string[] | object[],
@@ -166,6 +179,44 @@ export type AbstractModuleService<
sharedContext?: Context sharedContext?: Context
): Promise<Record<string, string[]> | void> ): Promise<Record<string, string[]> | void>
} }
} & {
[ModelName in keyof ModelsConfig as CreateMethodName<
ModelsConfig,
ModelName
>]: {
(
data: ModelsConfig[ModelName]["create"][],
sharedContext?: Context
): Promise<ModelsConfig[ModelName]["dto"][]>
}
} & {
[ModelName in keyof ModelsConfig as CreateMethodName<
ModelsConfig,
ModelName
>]: {
(data: ModelsConfig[ModelName]["create"], sharedContext?: Context): Promise<
ModelsConfig[ModelName]["dto"]
>
}
} & {
[ModelName in keyof ModelsConfig as UpdateMethodName<
ModelsConfig,
ModelName
>]: {
(
data: ModelsConfig[ModelName]["update"][],
sharedContext?: Context
): Promise<ModelsConfig[ModelName]["dto"][]>
}
} & {
[ModelName in keyof ModelsConfig as UpdateMethodName<
ModelsConfig,
ModelName
>]: {
(data: ModelsConfig[ModelName]["update"], sharedContext?: Context): Promise<
ModelsConfig[ModelName]["dto"]
>
}
} }
/** /**
@@ -211,7 +262,7 @@ export type AbstractModuleService<
export function abstractModuleServiceFactory< export function abstractModuleServiceFactory<
TContainer, TContainer,
TMainModelDTO, TMainModelDTO,
TOtherModelNamesAndAssociatedDTO extends ModelsConfigTemplate ModelsConfig extends ModelsConfigTemplate
>( >(
mainModel: Constructor<any>, mainModel: Constructor<any>,
otherModels: ModelConfiguration[], otherModels: ModelConfiguration[],
@@ -220,7 +271,7 @@ export function abstractModuleServiceFactory<
new (container: TContainer): AbstractModuleService< new (container: TContainer): AbstractModuleService<
TContainer, TContainer,
TMainModelDTO, TMainModelDTO,
TOtherModelNamesAndAssociatedDTO ModelsConfig
> >
} { } {
const buildMethodNamesFromModel = ( const buildMethodNamesFromModel = (
@@ -303,6 +354,44 @@ export function abstractModuleServiceFactory<
applyMethod(methodImplementation, 2) 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 break
case "list": case "list":
methodImplementation = async function <T extends object>( methodImplementation = async function <T extends object>(
@@ -532,9 +621,5 @@ export function abstractModuleServiceFactory<
return AbstractModuleService_ as unknown as new ( return AbstractModuleService_ as unknown as new (
container: TContainer container: TContainer
) => AbstractModuleService< ) => AbstractModuleService<TContainer, TMainModelDTO, ModelsConfig>
TContainer,
TMainModelDTO,
TOtherModelNamesAndAssociatedDTO
>
} }