Skip to content

Commit

Permalink
feat(utils): autogenerates create and update methods when dto is prov…
Browse files Browse the repository at this point in the history
…ided (#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.
  • Loading branch information
riqwan authored Mar 20, 2024
1 parent 64c2731 commit 4974f5e
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 104 deletions.
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
Expand Up @@ -94,13 +94,21 @@ export default class PricingModuleService<
InjectedDependencies,
PricingTypes.PriceSetDTO,
{
MoneyAmount: { dto: PricingTypes.MoneyAmountDTO }
MoneyAmount: {
dto: PricingTypes.MoneyAmountDTO
create: PricingTypes.CreateMoneyAmountDTO
update: PricingTypes.UpdateMoneyAmountDTO
}
PriceSetMoneyAmount: { dto: PricingTypes.PriceSetMoneyAmountDTO }
PriceSetMoneyAmountRules: {
dto: PricingTypes.PriceSetMoneyAmountRulesDTO
}
PriceRule: { dto: PricingTypes.PriceRuleDTO }
RuleType: { dto: PricingTypes.RuleTypeDTO }
RuleType: {
dto: PricingTypes.RuleTypeDTO
create: PricingTypes.CreateRuleTypeDTO
update: PricingTypes.UpdateRuleTypeDTO
}
PriceList: { dto: PricingTypes.PriceListDTO }
PriceListRule: { dto: PricingTypes.PriceListRuleDTO }
}
Expand Down Expand Up @@ -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[],
Expand Down
10 changes: 10 additions & 0 deletions packages/types/src/pricing/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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.
*
Expand Down
157 changes: 121 additions & 36 deletions packages/utils/src/modules-sdk/abstract-module-service-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import {
SoftDeleteReturn,
} from "@medusajs/types"
import {
MapToConfig,
isString,
kebabCase,
lowerCaseFirst,
mapObjectTo,
MapToConfig,
pluralize,
upperCaseFirst,
} from "../common"
Expand All @@ -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?: object
update?: 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?: 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 {
plural?: string
}
Expand Down Expand Up @@ -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[],
Expand All @@ -155,17 +171,52 @@ 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"][],
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"]
>
}
}

/**
Expand Down Expand Up @@ -211,7 +262,7 @@ export type AbstractModuleService<
export function abstractModuleServiceFactory<
TContainer,
TMainModelDTO,
TOtherModelNamesAndAssociatedDTO extends ModelsConfigTemplate
ModelsConfig extends ModelsConfigTemplate
>(
mainModel: Constructor<any>,
otherModels: ModelConfiguration[],
Expand All @@ -220,7 +271,7 @@ export function abstractModuleServiceFactory<
new (container: TContainer): AbstractModuleService<
TContainer,
TMainModelDTO,
TOtherModelNamesAndAssociatedDTO
ModelsConfig
>
} {
const buildMethodNamesFromModel = (
Expand Down Expand Up @@ -303,6 +354,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>(
Expand Down Expand Up @@ -532,9 +621,5 @@ export function abstractModuleServiceFactory<

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

0 comments on commit 4974f5e

Please sign in to comment.