feat: Make the Module require the service name (#7923)
* feat: Make the Module require the service name * finalize types
This commit is contained in:
1 parent
fdee0bd55a
commit
2711012d96
5 files changed
+160
-34
No files matched your search
@@ -458,45 +458,61 @@ describe("joiner-config-builder", () => {
|
|||||||
number_plate: model.text().primaryKey(),
|
number_plate: model.text().primaryKey(),
|
||||||
})
|
})
|
||||||
|
|
||||||
const linkConfig = buildLinkConfigFromDmlObjects([user, car])
|
const linkConfig = buildLinkConfigFromDmlObjects("myService", [user, car])
|
||||||
|
|
||||||
expectTypeOf(linkConfig).toMatchTypeOf<{
|
expectTypeOf(linkConfig).toMatchTypeOf<{
|
||||||
user: {
|
user: {
|
||||||
id: {
|
id: {
|
||||||
|
serviceName: "myService"
|
||||||
|
field: "user"
|
||||||
linkable: "user_id"
|
linkable: "user_id"
|
||||||
primaryKey: "id"
|
primaryKey: "id"
|
||||||
}
|
}
|
||||||
toJSON: () => {
|
toJSON: () => {
|
||||||
linkable: string
|
serviceName: "myService"
|
||||||
primaryKey: string
|
field: "user"
|
||||||
|
linkable: "user_id"
|
||||||
|
primaryKey: "id"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
car: {
|
car: {
|
||||||
number_plate: {
|
number_plate: {
|
||||||
|
serviceName: "myService"
|
||||||
|
field: "car"
|
||||||
linkable: "car_number_plate"
|
linkable: "car_number_plate"
|
||||||
primaryKey: "number_plate"
|
primaryKey: "number_plate"
|
||||||
}
|
}
|
||||||
toJSON: () => {
|
toJSON: () => {
|
||||||
linkable: string
|
serviceName: "myService"
|
||||||
primaryKey: string
|
field: "car"
|
||||||
|
linkable: "car_number_plate"
|
||||||
|
primaryKey: "number_plate"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
expect(linkConfig.user.id).toEqual({
|
expect(linkConfig.user.id).toEqual({
|
||||||
|
serviceName: "myService",
|
||||||
|
field: "user",
|
||||||
linkable: "user_id",
|
linkable: "user_id",
|
||||||
primaryKey: "id",
|
primaryKey: "id",
|
||||||
})
|
})
|
||||||
expect(linkConfig.car.number_plate).toEqual({
|
expect(linkConfig.car.number_plate).toEqual({
|
||||||
|
serviceName: "myService",
|
||||||
|
field: "car",
|
||||||
linkable: "car_number_plate",
|
linkable: "car_number_plate",
|
||||||
primaryKey: "number_plate",
|
primaryKey: "number_plate",
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(linkConfig.car.toJSON()).toEqual({
|
expect(linkConfig.car.toJSON()).toEqual({
|
||||||
|
serviceName: "myService",
|
||||||
|
field: "car",
|
||||||
linkable: "car_number_plate",
|
linkable: "car_number_plate",
|
||||||
primaryKey: "number_plate",
|
primaryKey: "number_plate",
|
||||||
})
|
})
|
||||||
expect(linkConfig.user.toJSON()).toEqual({
|
expect(linkConfig.user.toJSON()).toEqual({
|
||||||
|
serviceName: "myService",
|
||||||
|
field: "user",
|
||||||
linkable: "user_id",
|
linkable: "user_id",
|
||||||
primaryKey: "id",
|
primaryKey: "id",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import { InferLinkableKeys, InfersLinksConfig } from "./types/links-config"
|
|||||||
* The aliases will be built from the entityQueryingConfig and custom aliases if provided, in case of aliases provided if the methodSuffix is not provided
|
* The aliases will be built from the entityQueryingConfig and custom aliases if provided, in case of aliases provided if the methodSuffix is not provided
|
||||||
* then it will be inferred from the entity name of the alias args.
|
* then it will be inferred from the entity name of the alias args.
|
||||||
*
|
*
|
||||||
* @param moduleName
|
* @param serviceName
|
||||||
* @param alias
|
* @param alias
|
||||||
* @param schema
|
* @param schema
|
||||||
* @param models
|
* @param models
|
||||||
@@ -35,7 +35,7 @@ import { InferLinkableKeys, InfersLinksConfig } from "./types/links-config"
|
|||||||
* @param primaryKeys
|
* @param primaryKeys
|
||||||
*/
|
*/
|
||||||
export function defineJoinerConfig(
|
export function defineJoinerConfig(
|
||||||
moduleName: string,
|
serviceName: string,
|
||||||
{
|
{
|
||||||
alias,
|
alias,
|
||||||
schema,
|
schema,
|
||||||
@@ -108,7 +108,7 @@ export function defineJoinerConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!primaryKeys && modelDefinitions.size) {
|
if (!primaryKeys && modelDefinitions.size) {
|
||||||
const linkConfig = buildLinkConfigFromDmlObjects([
|
const linkConfig = buildLinkConfigFromDmlObjects(serviceName, [
|
||||||
...modelDefinitions.values(),
|
...modelDefinitions.values(),
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ export function defineJoinerConfig(
|
|||||||
// TODO: In the context of DML add a validation on primary keys and linkable keys if the consumer provide them manually. follow up pr
|
// TODO: In the context of DML add a validation on primary keys and linkable keys if the consumer provide them manually. follow up pr
|
||||||
|
|
||||||
return {
|
return {
|
||||||
serviceName: moduleName,
|
serviceName,
|
||||||
primaryKeys: primaryKeys ?? ["id"],
|
primaryKeys: primaryKeys ?? ["id"],
|
||||||
schema,
|
schema,
|
||||||
linkableKeys: linkableKeys,
|
linkableKeys: linkableKeys,
|
||||||
@@ -250,23 +250,41 @@ export function buildLinkableKeysFromMikroOrmObjects(
|
|||||||
* test: model.text(),
|
* test: model.text(),
|
||||||
* })
|
* })
|
||||||
*
|
*
|
||||||
|
* const links = buildLinkConfigFromDmlObjects('userService', [user, car])
|
||||||
|
*
|
||||||
* // output:
|
* // output:
|
||||||
* // {
|
* // {
|
||||||
* // toJSON: function () { },
|
|
||||||
* // user: {
|
* // user: {
|
||||||
* // id: "user_id",
|
* // id: {
|
||||||
|
* // serviceName: 'userService',
|
||||||
|
* // field: 'user',
|
||||||
|
* // linkable: 'user_id',
|
||||||
|
* // primaryKey: 'id'
|
||||||
|
* // },
|
||||||
|
* // toJSON() { ... }
|
||||||
* // },
|
* // },
|
||||||
* // car: {
|
* // car: {
|
||||||
* // number_plate: "car_number_plate",
|
* // number_plate: {
|
||||||
|
* // serviceName: 'userService',
|
||||||
|
* // field: 'car',
|
||||||
|
* // linkable: 'car_number_plate',
|
||||||
|
* // primaryKey: 'number_plate'
|
||||||
* // },
|
* // },
|
||||||
|
* // toJSON() { ... }
|
||||||
|
* // }
|
||||||
* // }
|
* // }
|
||||||
*
|
*
|
||||||
|
* @param serviceName
|
||||||
* @param models
|
* @param models
|
||||||
*/
|
*/
|
||||||
export function buildLinkConfigFromDmlObjects<
|
export function buildLinkConfigFromDmlObjects<
|
||||||
|
const ServiceName extends string,
|
||||||
const T extends DmlEntity<any, any>[]
|
const T extends DmlEntity<any, any>[]
|
||||||
>(models: T = [] as unknown as T): InfersLinksConfig<T> {
|
>(
|
||||||
const linkConfig = {} as InfersLinksConfig<T>
|
serviceName: ServiceName,
|
||||||
|
models: T = [] as unknown as T
|
||||||
|
): InfersLinksConfig<ServiceName, T> {
|
||||||
|
const linkConfig = {} as InfersLinksConfig<ServiceName, T>
|
||||||
|
|
||||||
for (const model of models) {
|
for (const model of models) {
|
||||||
if (!DmlEntity.isDmlEntity(model)) {
|
if (!DmlEntity.isDmlEntity(model)) {
|
||||||
@@ -297,12 +315,14 @@ export function buildLinkConfigFromDmlObjects<
|
|||||||
modelLinkConfig[property] = {
|
modelLinkConfig[property] = {
|
||||||
linkable: linkableKeyName,
|
linkable: linkableKeyName,
|
||||||
primaryKey: property,
|
primaryKey: property,
|
||||||
|
serviceName,
|
||||||
|
field: lowerCaseFirst(model.name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return linkConfig as InfersLinksConfig<T> & Record<any, any>
|
return linkConfig as InfersLinksConfig<ServiceName, T> & Record<any, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ import { DmlEntity } from "../dml"
|
|||||||
/**
|
/**
|
||||||
* Wrapper to build the module export and auto generate the joiner config if needed as well as
|
* Wrapper to build the module export and auto generate the joiner config if needed as well as
|
||||||
* return a links object based on the DML objects
|
* return a links object based on the DML objects
|
||||||
* @param moduleName
|
*
|
||||||
|
* @param serviceName
|
||||||
* @param service
|
* @param service
|
||||||
* @param loaders
|
* @param loaders
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
export function Module<
|
export function Module<
|
||||||
|
const ServiceName extends string,
|
||||||
const Service extends Constructor<any>,
|
const Service extends Constructor<any>,
|
||||||
const ModelObjects extends DmlEntity<any, any>[] = Service extends {
|
const ModelObjects extends DmlEntity<any, any>[] = Service extends {
|
||||||
$modelObjects: infer $DmlObjects
|
$modelObjects: infer $DmlObjects
|
||||||
@@ -24,22 +26,21 @@ export function Module<
|
|||||||
: [],
|
: [],
|
||||||
Links = keyof ModelObjects extends never
|
Links = keyof ModelObjects extends never
|
||||||
? Record<string, any>
|
? Record<string, any>
|
||||||
: InfersLinksConfig<ModelObjects>
|
: InfersLinksConfig<ServiceName, ModelObjects>
|
||||||
>({
|
>(
|
||||||
name = "",
|
serviceName: ServiceName,
|
||||||
service,
|
{ service, loaders }: ModuleExports<Service>
|
||||||
loaders,
|
): ModuleExports<Service> & {
|
||||||
}: ModuleExports<Service> & { name?: string }): ModuleExports<Service> & {
|
|
||||||
links: Links
|
links: Links
|
||||||
} {
|
} {
|
||||||
service.prototype.__joinerConfig ??= defineJoinerConfig(name)
|
service.prototype.__joinerConfig ??= defineJoinerConfig(serviceName)
|
||||||
|
|
||||||
const dmlObjects = service[MedusaServiceModelObjectsSymbol]
|
const dmlObjects = service[MedusaServiceModelObjectsSymbol]
|
||||||
return {
|
return {
|
||||||
service,
|
service,
|
||||||
loaders,
|
loaders,
|
||||||
links: (dmlObjects?.length
|
links: (dmlObjects?.length
|
||||||
? buildLinkConfigFromDmlObjects(dmlObjects)
|
? buildLinkConfigFromDmlObjects<ServiceName, ModelObjects>(dmlObjects)
|
||||||
: {}) as Links,
|
: {}) as Links,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,10 @@ import {
|
|||||||
import { DmlEntity } from "../../dml"
|
import { DmlEntity } from "../../dml"
|
||||||
import { PrimaryKeyModifier } from "../../dml/properties/primary-key"
|
import { PrimaryKeyModifier } from "../../dml/properties/primary-key"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utils
|
||||||
|
*/
|
||||||
|
|
||||||
type FlattenUnion<T> = T extends { [K in keyof T]: infer U }
|
type FlattenUnion<T> = T extends { [K in keyof T]: infer U }
|
||||||
? { [K in keyof T]: U }
|
? { [K in keyof T]: U }
|
||||||
: never
|
: never
|
||||||
@@ -17,6 +21,30 @@ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
|||||||
? I
|
? I
|
||||||
: never
|
: never
|
||||||
|
|
||||||
|
type UnionToOvlds<U> = UnionToIntersection<
|
||||||
|
U extends any ? (f: U) => void : never
|
||||||
|
>
|
||||||
|
|
||||||
|
type PopUnion<U> = UnionToOvlds<U> extends (a: infer A) => void ? A : never
|
||||||
|
|
||||||
|
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true
|
||||||
|
|
||||||
|
type UnionToArray<T, A extends unknown[] = []> = IsUnion<T> extends true
|
||||||
|
? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
|
||||||
|
: [T, ...A]
|
||||||
|
|
||||||
|
type Reverse<T extends unknown[], R extends unknown[] = []> = ReturnType<
|
||||||
|
T extends [infer F, ...infer L] ? () => Reverse<L, [F, ...R]> : () => R
|
||||||
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End of utils
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Linkable keys
|
||||||
|
*/
|
||||||
|
|
||||||
type InferLinkableKeyName<
|
type InferLinkableKeyName<
|
||||||
Key,
|
Key,
|
||||||
Property,
|
Property,
|
||||||
@@ -67,16 +95,61 @@ type AggregateSchemasLinkableKeys<T extends DmlEntity<any, any>[]> = {
|
|||||||
export type InferLinkableKeys<T extends DmlEntity<any, any>[]> =
|
export type InferLinkableKeys<T extends DmlEntity<any, any>[]> =
|
||||||
UnionToIntersection<FlattenUnion<AggregateSchemasLinkableKeys<T>>[0]>
|
UnionToIntersection<FlattenUnion<AggregateSchemasLinkableKeys<T>>[0]>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End Linkable keys
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Links config
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From a union infer an Array and return the last element
|
||||||
|
*/
|
||||||
|
type InferLastLink<ServiceName extends string, DmlEntity> = UnionToArray<
|
||||||
|
| InferSchemaLinksConfig<ServiceName, DmlEntity>[keyof InferSchemaLinksConfig<
|
||||||
|
ServiceName,
|
||||||
|
DmlEntity
|
||||||
|
>]
|
||||||
|
> extends [...any, infer V]
|
||||||
|
? V
|
||||||
|
: never
|
||||||
|
|
||||||
|
type InferLastPrimaryKey<ServiceName extends string, DmlEntity> = InferLastLink<
|
||||||
|
ServiceName,
|
||||||
|
DmlEntity
|
||||||
|
> extends {
|
||||||
|
primaryKey: infer PrimaryKey
|
||||||
|
}
|
||||||
|
? PrimaryKey
|
||||||
|
: string
|
||||||
|
|
||||||
|
type InferLastLinkable<ServiceName extends string, DmlEntity> = InferLastLink<
|
||||||
|
ServiceName,
|
||||||
|
DmlEntity
|
||||||
|
> extends {
|
||||||
|
linkable: infer Linkable
|
||||||
|
}
|
||||||
|
? Linkable
|
||||||
|
: string
|
||||||
|
|
||||||
type InferPrimaryKeyNameOrNever<
|
type InferPrimaryKeyNameOrNever<
|
||||||
Schema extends DMLSchema,
|
Schema extends DMLSchema,
|
||||||
Key extends keyof Schema
|
Key extends keyof Schema
|
||||||
> = Schema[Key] extends PrimaryKeyModifier<any, any> ? Key : never
|
> = Schema[Key] extends PrimaryKeyModifier<any, any> ? Key : never
|
||||||
|
|
||||||
type InferSchemaLinksConfig<T> = T extends DmlEntity<infer Schema, infer Config>
|
type InferSchemaLinksConfig<
|
||||||
|
ServiceName extends string,
|
||||||
|
T
|
||||||
|
> = T extends DmlEntity<infer Schema, infer Config>
|
||||||
? {
|
? {
|
||||||
[K in keyof Schema as Schema[K] extends PrimaryKeyModifier<any, any>
|
[K in keyof Schema as Schema[K] extends PrimaryKeyModifier<any, any>
|
||||||
? InferPrimaryKeyNameOrNever<Schema, K>
|
? InferPrimaryKeyNameOrNever<Schema, K>
|
||||||
: never]: {
|
: never]: {
|
||||||
|
serviceName: ServiceName
|
||||||
|
field: T extends DmlEntity<any, infer Config>
|
||||||
|
? Uncapitalize<InferDmlEntityNameFromConfig<Config>>
|
||||||
|
: string
|
||||||
linkable: InferLinkableKeyName<K, Schema[K], Config>
|
linkable: InferLinkableKeyName<K, Schema[K], Config>
|
||||||
primaryKey: K
|
primaryKey: K
|
||||||
}
|
}
|
||||||
@@ -84,7 +157,10 @@ type InferSchemaLinksConfig<T> = T extends DmlEntity<infer Schema, infer Config>
|
|||||||
: {}
|
: {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From an array of DmlEntity, returns a formatted object with the linkable keys
|
* From an array of DmlEntity, returns a formatted links object.
|
||||||
|
* the toJSON of each object representation will return the last linkable definition
|
||||||
|
* as the default. To specify a specific linkable, you can chain until the desired linkable property.
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* @example:
|
* @example:
|
||||||
*
|
*
|
||||||
@@ -103,6 +179,8 @@ type InferSchemaLinksConfig<T> = T extends DmlEntity<infer Schema, infer Config>
|
|||||||
* // {
|
* // {
|
||||||
* // user: {
|
* // user: {
|
||||||
* // id: {
|
* // id: {
|
||||||
|
* // serviceName: 'userService',
|
||||||
|
* // field: 'user',
|
||||||
* // linkable: 'user_id',
|
* // linkable: 'user_id',
|
||||||
* // primaryKey: 'id'
|
* // primaryKey: 'id'
|
||||||
* // },
|
* // },
|
||||||
@@ -110,6 +188,8 @@ type InferSchemaLinksConfig<T> = T extends DmlEntity<infer Schema, infer Config>
|
|||||||
* // },
|
* // },
|
||||||
* // car: {
|
* // car: {
|
||||||
* // number_plate: {
|
* // number_plate: {
|
||||||
|
* // serviceName: 'userService',
|
||||||
|
* // field: 'car',
|
||||||
* // linkable: 'car_number_plate',
|
* // linkable: 'car_number_plate',
|
||||||
* // primaryKey: 'number_plate'
|
* // primaryKey: 'number_plate'
|
||||||
* // },
|
* // },
|
||||||
@@ -118,14 +198,24 @@ type InferSchemaLinksConfig<T> = T extends DmlEntity<infer Schema, infer Config>
|
|||||||
* // }
|
* // }
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export type InfersLinksConfig<T extends DmlEntity<any, any>[]> =
|
export type InfersLinksConfig<
|
||||||
UnionToIntersection<{
|
ServiceName extends string,
|
||||||
|
T extends DmlEntity<any, any>[]
|
||||||
|
> = UnionToIntersection<{
|
||||||
[K in keyof T as T[K] extends DmlEntity<any, infer Config>
|
[K in keyof T as T[K] extends DmlEntity<any, infer Config>
|
||||||
? Uncapitalize<InferDmlEntityNameFromConfig<Config>>
|
? Uncapitalize<InferDmlEntityNameFromConfig<Config>>
|
||||||
: never]: InferSchemaLinksConfig<T[K]> & {
|
: never]: InferSchemaLinksConfig<ServiceName, T[K]> & {
|
||||||
toJSON: () => {
|
toJSON: () => {
|
||||||
linkable: string
|
serviceName: ServiceName
|
||||||
primaryKey: string
|
field: T[K] extends DmlEntity<any, infer Config>
|
||||||
|
? Uncapitalize<InferDmlEntityNameFromConfig<Config>>
|
||||||
|
: string
|
||||||
|
linkable: InferLastLinkable<ServiceName, T[K]>
|
||||||
|
primaryKey: InferLastPrimaryKey<ServiceName, T[K]>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}>
|
}>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End Links config
|
||||||
|
*/
|
||||||
@@ -5,8 +5,7 @@ import { Module, Modules } from "@medusajs/utils"
|
|||||||
const service = CurrencyModuleService
|
const service = CurrencyModuleService
|
||||||
const loaders = [initialDataLoader]
|
const loaders = [initialDataLoader]
|
||||||
|
|
||||||
export default Module({
|
export default Module(Modules.CURRENCY, {
|
||||||
name: Modules.CURRENCY,
|
|
||||||
service,
|
service,
|
||||||
loaders,
|
loaders,
|
||||||
})
|
})
|
||||||
Reference in new issue
Block a user