feat: Make the Module require the service name (#7923)
* feat: Make the Module require the service name * finalize types
This commit is contained in:
committed by
GitHub
parent
fdee0bd55a
commit
2711012d96
@@ -458,45 +458,61 @@ describe("joiner-config-builder", () => {
|
||||
number_plate: model.text().primaryKey(),
|
||||
})
|
||||
|
||||
const linkConfig = buildLinkConfigFromDmlObjects([user, car])
|
||||
const linkConfig = buildLinkConfigFromDmlObjects("myService", [user, car])
|
||||
|
||||
expectTypeOf(linkConfig).toMatchTypeOf<{
|
||||
user: {
|
||||
id: {
|
||||
serviceName: "myService"
|
||||
field: "user"
|
||||
linkable: "user_id"
|
||||
primaryKey: "id"
|
||||
}
|
||||
toJSON: () => {
|
||||
linkable: string
|
||||
primaryKey: string
|
||||
serviceName: "myService"
|
||||
field: "user"
|
||||
linkable: "user_id"
|
||||
primaryKey: "id"
|
||||
}
|
||||
}
|
||||
car: {
|
||||
number_plate: {
|
||||
serviceName: "myService"
|
||||
field: "car"
|
||||
linkable: "car_number_plate"
|
||||
primaryKey: "number_plate"
|
||||
}
|
||||
toJSON: () => {
|
||||
linkable: string
|
||||
primaryKey: string
|
||||
serviceName: "myService"
|
||||
field: "car"
|
||||
linkable: "car_number_plate"
|
||||
primaryKey: "number_plate"
|
||||
}
|
||||
}
|
||||
}>()
|
||||
|
||||
expect(linkConfig.user.id).toEqual({
|
||||
serviceName: "myService",
|
||||
field: "user",
|
||||
linkable: "user_id",
|
||||
primaryKey: "id",
|
||||
})
|
||||
expect(linkConfig.car.number_plate).toEqual({
|
||||
serviceName: "myService",
|
||||
field: "car",
|
||||
linkable: "car_number_plate",
|
||||
primaryKey: "number_plate",
|
||||
})
|
||||
|
||||
expect(linkConfig.car.toJSON()).toEqual({
|
||||
serviceName: "myService",
|
||||
field: "car",
|
||||
linkable: "car_number_plate",
|
||||
primaryKey: "number_plate",
|
||||
})
|
||||
expect(linkConfig.user.toJSON()).toEqual({
|
||||
serviceName: "myService",
|
||||
field: "user",
|
||||
linkable: "user_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
|
||||
* then it will be inferred from the entity name of the alias args.
|
||||
*
|
||||
* @param moduleName
|
||||
* @param serviceName
|
||||
* @param alias
|
||||
* @param schema
|
||||
* @param models
|
||||
@@ -35,7 +35,7 @@ import { InferLinkableKeys, InfersLinksConfig } from "./types/links-config"
|
||||
* @param primaryKeys
|
||||
*/
|
||||
export function defineJoinerConfig(
|
||||
moduleName: string,
|
||||
serviceName: string,
|
||||
{
|
||||
alias,
|
||||
schema,
|
||||
@@ -108,7 +108,7 @@ export function defineJoinerConfig(
|
||||
}
|
||||
|
||||
if (!primaryKeys && modelDefinitions.size) {
|
||||
const linkConfig = buildLinkConfigFromDmlObjects([
|
||||
const linkConfig = buildLinkConfigFromDmlObjects(serviceName, [
|
||||
...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
|
||||
|
||||
return {
|
||||
serviceName: moduleName,
|
||||
serviceName,
|
||||
primaryKeys: primaryKeys ?? ["id"],
|
||||
schema,
|
||||
linkableKeys: linkableKeys,
|
||||
@@ -250,23 +250,41 @@ export function buildLinkableKeysFromMikroOrmObjects(
|
||||
* test: model.text(),
|
||||
* })
|
||||
*
|
||||
* const links = buildLinkConfigFromDmlObjects('userService', [user, car])
|
||||
*
|
||||
* // output:
|
||||
* // {
|
||||
* // toJSON: function () { },
|
||||
* // user: {
|
||||
* // id: "user_id",
|
||||
* // id: {
|
||||
* // serviceName: 'userService',
|
||||
* // field: 'user',
|
||||
* // linkable: 'user_id',
|
||||
* // primaryKey: 'id'
|
||||
* // },
|
||||
* // toJSON() { ... }
|
||||
* // },
|
||||
* // car: {
|
||||
* // number_plate: "car_number_plate",
|
||||
* // },
|
||||
* // number_plate: {
|
||||
* // serviceName: 'userService',
|
||||
* // field: 'car',
|
||||
* // linkable: 'car_number_plate',
|
||||
* // primaryKey: 'number_plate'
|
||||
* // },
|
||||
* // toJSON() { ... }
|
||||
* // }
|
||||
* // }
|
||||
*
|
||||
* @param serviceName
|
||||
* @param models
|
||||
*/
|
||||
export function buildLinkConfigFromDmlObjects<
|
||||
const ServiceName extends string,
|
||||
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) {
|
||||
if (!DmlEntity.isDmlEntity(model)) {
|
||||
@@ -297,12 +315,14 @@ export function buildLinkConfigFromDmlObjects<
|
||||
modelLinkConfig[property] = {
|
||||
linkable: linkableKeyName,
|
||||
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
|
||||
* return a links object based on the DML objects
|
||||
* @param moduleName
|
||||
*
|
||||
* @param serviceName
|
||||
* @param service
|
||||
* @param loaders
|
||||
* @constructor
|
||||
*/
|
||||
export function Module<
|
||||
const ServiceName extends string,
|
||||
const Service extends Constructor<any>,
|
||||
const ModelObjects extends DmlEntity<any, any>[] = Service extends {
|
||||
$modelObjects: infer $DmlObjects
|
||||
@@ -24,22 +26,21 @@ export function Module<
|
||||
: [],
|
||||
Links = keyof ModelObjects extends never
|
||||
? Record<string, any>
|
||||
: InfersLinksConfig<ModelObjects>
|
||||
>({
|
||||
name = "",
|
||||
service,
|
||||
loaders,
|
||||
}: ModuleExports<Service> & { name?: string }): ModuleExports<Service> & {
|
||||
: InfersLinksConfig<ServiceName, ModelObjects>
|
||||
>(
|
||||
serviceName: ServiceName,
|
||||
{ service, loaders }: ModuleExports<Service>
|
||||
): ModuleExports<Service> & {
|
||||
links: Links
|
||||
} {
|
||||
service.prototype.__joinerConfig ??= defineJoinerConfig(name)
|
||||
service.prototype.__joinerConfig ??= defineJoinerConfig(serviceName)
|
||||
|
||||
const dmlObjects = service[MedusaServiceModelObjectsSymbol]
|
||||
return {
|
||||
service,
|
||||
loaders,
|
||||
links: (dmlObjects?.length
|
||||
? buildLinkConfigFromDmlObjects(dmlObjects)
|
||||
? buildLinkConfigFromDmlObjects<ServiceName, ModelObjects>(dmlObjects)
|
||||
: {}) as Links,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,10 @@ import {
|
||||
import { DmlEntity } from "../../dml"
|
||||
import { PrimaryKeyModifier } from "../../dml/properties/primary-key"
|
||||
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
|
||||
type FlattenUnion<T> = T extends { [K in keyof T]: infer U }
|
||||
? { [K in keyof T]: U }
|
||||
: never
|
||||
@@ -17,6 +21,30 @@ type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
||||
? I
|
||||
: 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<
|
||||
Key,
|
||||
Property,
|
||||
@@ -67,16 +95,61 @@ type AggregateSchemasLinkableKeys<T extends DmlEntity<any, any>[]> = {
|
||||
export type InferLinkableKeys<T extends DmlEntity<any, any>[]> =
|
||||
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<
|
||||
Schema extends DMLSchema,
|
||||
Key extends keyof Schema
|
||||
> = 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>
|
||||
? InferPrimaryKeyNameOrNever<Schema, K>
|
||||
: never]: {
|
||||
serviceName: ServiceName
|
||||
field: T extends DmlEntity<any, infer Config>
|
||||
? Uncapitalize<InferDmlEntityNameFromConfig<Config>>
|
||||
: string
|
||||
linkable: InferLinkableKeyName<K, Schema[K], Config>
|
||||
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:
|
||||
*
|
||||
@@ -103,6 +179,8 @@ type InferSchemaLinksConfig<T> = T extends DmlEntity<infer Schema, infer Config>
|
||||
* // {
|
||||
* // user: {
|
||||
* // id: {
|
||||
* // serviceName: 'userService',
|
||||
* // field: 'user',
|
||||
* // linkable: 'user_id',
|
||||
* // primaryKey: 'id'
|
||||
* // },
|
||||
@@ -110,6 +188,8 @@ type InferSchemaLinksConfig<T> = T extends DmlEntity<infer Schema, infer Config>
|
||||
* // },
|
||||
* // car: {
|
||||
* // number_plate: {
|
||||
* // serviceName: 'userService',
|
||||
* // field: 'car',
|
||||
* // linkable: 'car_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>[]> =
|
||||
UnionToIntersection<{
|
||||
[K in keyof T as T[K] extends DmlEntity<any, infer Config>
|
||||
? Uncapitalize<InferDmlEntityNameFromConfig<Config>>
|
||||
: never]: InferSchemaLinksConfig<T[K]> & {
|
||||
toJSON: () => {
|
||||
linkable: string
|
||||
primaryKey: string
|
||||
}
|
||||
export type InfersLinksConfig<
|
||||
ServiceName extends string,
|
||||
T extends DmlEntity<any, any>[]
|
||||
> = UnionToIntersection<{
|
||||
[K in keyof T as T[K] extends DmlEntity<any, infer Config>
|
||||
? Uncapitalize<InferDmlEntityNameFromConfig<Config>>
|
||||
: never]: InferSchemaLinksConfig<ServiceName, T[K]> & {
|
||||
toJSON: () => {
|
||||
serviceName: ServiceName
|
||||
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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user