feat: refactor module joiner config and links generation (#7859)

* feat: refactor module joiner config and links generation

* improve typings

* WIP

* WIP

* WIP

* rename type file

* create link config

* finish typings and add utils

* improve links

* WIP typings

* finalize ExportModule utils

* finalize ExportModule utils

* fix: dml tests

* improve and fixes

* simplify typings with id changes

* add toJSON

* multiple fixes and entity builder fixes

* fix currency searchable

* fix tests

* medusa service refactoring

* cleanup

* cleanup and fixes

* make module name optional

* renaming

---------

Co-authored-by: Harminder Virk <virk.officials@gmail.com>
This commit is contained in:
Adrien de PerettiandHarminder Virk authored and GitHub committed 2024-07-03 13:12:49 +02:00
1 parent 5aa62e59e4
commit 617a5972bf
89 files changed
+1437 -681

No files matched your search

@@ -1,5 +1,6 @@
import { model } from "@medusajs/utils" import { model } from "@medusajs/utils"
export const dmlEntity = model.define("dmlEntity", { export const dmlEntity = model.define("dmlEntity", {
id: model.id().primaryKey(),
name: model.text(), name: model.text(),
}) })
@@ -1,5 +1,6 @@
import { model } from "@medusajs/utils" import { model } from "@medusajs/utils"
export const entityModel = model.define("entityModel", { export const entityModel = model.define("entityModel", {
id: model.id().primaryKey(),
name: model.text(), name: model.text(),
}) })
@@ -1,5 +1,6 @@
import { model } from "@medusajs/utils" import { model } from "@medusajs/utils"
export const dmlEntity = model.define("dmlEntity", { export const dmlEntity = model.define("dmlEntity", {
id: model.id().primaryKey(),
name: model.text(), name: model.text(),
}) })
@@ -11,11 +11,11 @@ import {
import { import {
ContainerRegistrationKeys, ContainerRegistrationKeys,
createMedusaContainer, createMedusaContainer,
createMikrORMEntity,
defineJoinerConfig, defineJoinerConfig,
DmlEntity, DmlEntity,
MedusaModuleType, MedusaModuleType,
ModulesSdkUtils, ModulesSdkUtils,
toMikroOrmEntities,
} from "@medusajs/utils" } from "@medusajs/utils"
import { asFunction, asValue } from "awilix" import { asFunction, asValue } from "awilix"
import { statSync } from "fs" import { statSync } from "fs"
@@ -270,12 +270,11 @@ export async function loadResources(
), ),
]) ])
const entityBuilder = createMikrORMEntity()
const cleanupResources = (resources) => { const cleanupResources = (resources) => {
return Object.values(resources) return Object.values(resources)
.map((resource) => { .map((resource) => {
if (DmlEntity.isDmlEntity(resource)) { if (DmlEntity.isDmlEntity(resource)) {
return entityBuilder(resource as DmlEntity<any>) return resource
} }
if (typeof resource === "function") { if (typeof resource === "function") {
@@ -289,11 +288,12 @@ export async function loadResources(
const potentialServices = [...new Set(cleanupResources(services))] const potentialServices = [...new Set(cleanupResources(services))]
const potentialModels = [...new Set(cleanupResources(models))] const potentialModels = [...new Set(cleanupResources(models))]
const mikroOrmModels = toMikroOrmEntities(potentialModels)
const potentialRepositories = [...new Set(cleanupResources(repositories))] const potentialRepositories = [...new Set(cleanupResources(repositories))]
const finalLoaders = prepareLoaders({ const finalLoaders = prepareLoaders({
loadedModuleLoaders, loadedModuleLoaders,
models: potentialModels, models: mikroOrmModels,
repositories: potentialRepositories, repositories: potentialRepositories,
services: potentialServices, services: potentialServices,
moduleResolution, moduleResolution,
@@ -308,7 +308,7 @@ export async function loadResources(
return { return {
services: potentialServices, services: potentialServices,
models: potentialModels, models: mikroOrmModels,
repositories: potentialRepositories, repositories: potentialRepositories,
loaders: finalLoaders, loaders: finalLoaders,
moduleService, moduleService,
@@ -433,15 +433,20 @@ function generateJoinerConfigIfNecessary({
}: { }: {
moduleResolution: ModuleResolution moduleResolution: ModuleResolution
service: Constructor<IModuleService> service: Constructor<IModuleService>
models: Function[] models: (Function | DmlEntity<any, any>)[]
}) { }) {
if (service.prototype.__joinerConfig) { const originalJoinerConfigFn = service.prototype.__joinerConfig
return
}
service.prototype.__joinerConfig = function () { service.prototype.__joinerConfig = function () {
if (originalJoinerConfigFn) {
return {
serviceName: moduleResolution.definition.key,
...originalJoinerConfigFn(),
}
}
return defineJoinerConfig(moduleResolution.definition.key, { return defineJoinerConfig(moduleResolution.definition.key, {
entityQueryingConfig: models, models,
}) })
} }
} }
@@ -0,0 +1,89 @@
type IsStringLiteral<Type> = Type extends string
? string extends Type
? false
: true
: false
type WordInCamelCase<
Type,
Word extends string = ""
> = Type extends `${Word}${infer NextCharacter}${infer _}`
? NextCharacter extends Capitalize<NextCharacter>
? Word
: WordInCamelCase<Type, `${Word}${NextCharacter}`>
: Word
type Separator = "_" | "-"
type IncludesSeparator<Type> = Type extends `${string}${Separator}${string}`
? true
: false
type IsOneWord<Type> = Type extends Lowercase<Type & string>
? true
: Type extends Uppercase<Type & string>
? true
: false
type IsCamelCase<Type> = Type extends Uncapitalize<Type & string> ? true : false
type IsPascalCase<Type> = Type extends Capitalize<Type & string> ? true : false
/** snake_case, CONSTANT_CASE, kebab-case or COBOL-CASE */
type SeparatorCaseParser<
Type,
Tuple extends readonly any[] = []
> = Type extends `${infer Word}${Separator}${infer Tail}`
? SeparatorCaseParser<Tail, [...Tuple, Lowercase<Word>]>
: Type extends `${infer Word}`
? [...Tuple, Lowercase<Word>]
: Tuple
type CamelCaseParser<Type, Tuple extends readonly any[] = []> = Type extends ""
? Tuple
: Type extends `${WordInCamelCase<Type>}${infer Tail}`
? Type extends `${infer Word}${Tail}`
? CamelCaseParser<Uncapitalize<Tail>, [...Tuple, Lowercase<Word>]>
: never
: never
// Convert first character of string literal type to lowercase and reuse CamelCaseParser
type PascalCaseParser<Type> = Type extends string
? CamelCaseParser<Uncapitalize<Type>>
: never
type SplitAnyCase<Type> = IncludesSeparator<Type> extends true
? SeparatorCaseParser<Type>
: IsOneWord<Type> extends true
? [Lowercase<Type & string>]
: IsCamelCase<Type> extends true
? CamelCaseParser<Type>
: IsPascalCase<Type> extends true
? PascalCaseParser<Type>
: []
type PascalCapitalizer<Type, Tuple extends readonly any[] = []> = Type extends [
infer Head,
...infer Tail
]
? Head extends string
? PascalCapitalizer<Tail, [...Tuple, Capitalize<Head>]>
: PascalCapitalizer<Tail, Tuple>
: Tuple
type CamelCapitalizer<Type> = Type extends [infer First, ...infer Tail]
? PascalCapitalizer<Tail, [First]>
: []
type Join<Type, JoinedString extends string = ""> = Type extends [
infer Head,
...infer Tail
]
? Head extends string
? Join<Tail, `${JoinedString}${Head}`>
: Join<Tail>
: JoinedString
export type CamelCase<Type> = IsStringLiteral<Type> extends true
? Join<CamelCapitalizer<SplitAnyCase<Type>>>
: Type
+1
View File
@@ -5,3 +5,4 @@ export * from "./config-module"
export * from "./medusa-cli" export * from "./medusa-cli"
export * from "./medusa-container" export * from "./medusa-container"
export * from "./with-calculated" export * from "./with-calculated"
export * from "./camel-case"
+35 -14
View File
@@ -1,3 +1,5 @@
import { CamelCase } from "../common"
/** /**
* Symbol to identify a DML entity from an object * Symbol to identify a DML entity from an object
*/ */
@@ -13,11 +15,26 @@ export type DMLSchema = Record<
PropertyType<any> | RelationshipType<any> PropertyType<any> | RelationshipType<any>
> >
export type IDmlEntityConfig = string | { name?: string; tableName: string }
export type InferDmlEntityNameFromConfig<TConfig extends IDmlEntityConfig> =
TConfig extends string
? Capitalize<CamelCase<TConfig>>
: TConfig extends { name: string }
? Capitalize<CamelCase<TConfig["name"] & string>>
: TConfig extends { tableName: string }
? Capitalize<CamelCase<TConfig["tableName"] & string>>
: never
/** /**
* Representation of a DML entity * Representation of a DML entity
*/ */
export interface IDmlEntity<Schema extends DMLSchema> { export interface IDmlEntity<
Schema extends DMLSchema,
Config extends IDmlEntityConfig
> {
[IsDmlEntity]: true [IsDmlEntity]: true
name: InferDmlEntityNameFromConfig<Config>
schema: Schema schema: Schema
} }
@@ -60,6 +77,7 @@ export type PropertyMetadata = {
type: "index" | "unique" type: "index" | "unique"
}[] }[]
relationships: RelationshipMetadata[] relationships: RelationshipMetadata[]
primaryKey?: boolean
} }
/** /**
@@ -125,22 +143,23 @@ export type InferForeignKeys<Schema extends DMLSchema> = {
[K in keyof Schema as Schema[K] extends { type: infer Type } [K in keyof Schema as Schema[K] extends { type: infer Type }
? Type extends RelationshipTypes ? Type extends RelationshipTypes
? `${K & string}_id` ? `${K & string}_id`
: K : never
: K]: Schema[K] extends { type: infer Type } : never]: Schema[K] extends { type: infer Type }
? Type extends RelationshipTypes ? Type extends RelationshipTypes
? string ? string
: Schema[K] : never
: Schema[K] : never
} }
/** /**
* Infer fields for a belongsTo relationship * Infer fields for a belongsTo relationship
*/ */
export type InferBelongsToFields<Relation> = Relation extends () => IDmlEntity< export type InferBelongsToFields<Relation> = Relation extends () => IDmlEntity<
infer R infer R,
any
> >
? InferSchemaFields<R> ? InferSchemaFields<R>
: Relation extends () => IDmlEntity<infer R> | null : Relation extends () => IDmlEntity<infer R, any> | null
? InferSchemaFields<R> | null ? InferSchemaFields<R> | null
: never : never
@@ -153,7 +172,8 @@ export type InferHasOneFields<Relation> = InferBelongsToFields<Relation>
* Infer fields for hasMany relationship * Infer fields for hasMany relationship
*/ */
export type InferHasManyFields<Relation> = Relation extends () => IDmlEntity< export type InferHasManyFields<Relation> = Relation extends () => IDmlEntity<
infer R infer R,
any
> >
? InferSchemaFields<R>[] ? InferSchemaFields<R>[]
: never : never
@@ -184,7 +204,7 @@ export type InferSchemaFields<Schema extends DMLSchema> = {
/** /**
* Helper to infer the schema type of a DmlEntity * Helper to infer the schema type of a DmlEntity
*/ */
export type Infer<T> = T extends IDmlEntity<infer Schema> export type Infer<T> = T extends IDmlEntity<infer Schema, any>
? EntityConstructor<InferSchemaFields<Schema>> ? EntityConstructor<InferSchemaFields<Schema>>
: never : never
@@ -217,12 +237,12 @@ export type EntityCascades<Relationships> = {
/** /**
* Helper to infer the instance type of a IDmlEntity once converted as an Entity * Helper to infer the instance type of a IDmlEntity once converted as an Entity
*/ */
export type InferTypeOf<T extends IDmlEntity<any>> = InstanceType<Infer<T>> export type InferTypeOf<T extends IDmlEntity<any, any>> = InstanceType<Infer<T>>
/** /**
* Used in the module sdk internal service to infer propert entity typings from DML * Used in the module sdk internal service to infer propert entity typings from DML
*/ */
export type InferEntityType<T extends any> = T extends IDmlEntity<any> export type InferEntityType<T> = T extends IDmlEntity<any, any>
? InferTypeOf<T> ? InferTypeOf<T>
: T : T
@@ -230,7 +250,8 @@ export type InferEntityType<T extends any> = T extends IDmlEntity<any>
* Infer all indexable properties from a DML entity including inferred foreign keys and excluding relationship * Infer all indexable properties from a DML entity including inferred foreign keys and excluding relationship
*/ */
export type InferIndexableProperties<T> = keyof (T extends IDmlEntity< export type InferIndexableProperties<T> = keyof (T extends IDmlEntity<
infer Schema infer Schema,
any
> >
? { ? {
[K in keyof Schema as Schema[K] extends { type: infer Type } [K in keyof Schema as Schema[K] extends { type: infer Type }
@@ -258,7 +279,7 @@ export type EntityIndex<
/** /**
* The list of properties to create the index on. * The list of properties to create the index on.
*/ */
on: InferIndexableProperties<IDmlEntity<TSchema>>[] on: InferIndexableProperties<IDmlEntity<TSchema, any>>[]
/** /**
* Conditions to restrict which records are indexed. * Conditions to restrict which records are indexed.
*/ */
@@ -270,7 +291,7 @@ export type NeQueryValue = { $ne: SimpleQueryValue }
export type QueryValue = SimpleQueryValue | NeQueryValue export type QueryValue = SimpleQueryValue | NeQueryValue
export type QueryCondition<T extends DMLSchema = DMLSchema> = { export type QueryCondition<T extends DMLSchema = DMLSchema> = {
[K in keyof IDmlEntity<T>["schema"]]?: T[K] extends object [K in keyof IDmlEntity<T, any>["schema"]]?: T[K] extends object
? QueryValue ? QueryValue
: QueryCondition<T> : QueryCondition<T>
} }
+2 -2
View File
@@ -224,8 +224,8 @@ export declare type ModuleJoinerRelationship = JoinerRelationship & {
deleteCascade?: boolean deleteCascade?: boolean
} }
export type ModuleExports = { export type ModuleExports<T = Constructor<any>> = {
service: Constructor<any> service: T
loaders?: ModuleLoaderFunction[] loaders?: ModuleLoaderFunction[]
runMigrations?( runMigrations?(
options: LoaderOptions<any>, options: LoaderOptions<any>,
@@ -1,5 +1,5 @@
export function toCamelCase(str: string): string { export function toCamelCase(str: string): string {
return /^([a-z]+)(([A-Z]([a-z]+))+)$/.test(str) return /^([a-zA-Z]+)(([A-Z]([a-z]+))+)$/.test(str)
? str ? str
: str : str
.toLowerCase() .toLowerCase()
@@ -34,7 +34,6 @@ describe("Base property", () => {
dataType: { dataType: {
name: "text", name: "text",
options: { options: {
primaryKey: false,
searchable: true, searchable: true,
}, },
}, },
@@ -1,4 +1,4 @@
import { ArrayType, MetadataStorage } from "@mikro-orm/core" import { ArrayType, EntityMetadata, MetadataStorage } from "@mikro-orm/core"
import { expectTypeOf } from "expect-type" import { expectTypeOf } from "expect-type"
import { DmlEntity } from "../entity" import { DmlEntity } from "../entity"
import { model } from "../entity-builder" import { model } from "../entity-builder"
@@ -72,7 +72,7 @@ describe("Entity builder", () => {
phones: model.array(), phones: model.array(),
}) })
expect(user.name).toEqual("user") expect(user.name).toEqual("User")
expect(user.parse().tableName).toEqual("user") expect(user.parse().tableName).toEqual("user")
const User = toMikroORMEntity(user) const User = toMikroORMEntity(user)
@@ -202,7 +202,7 @@ describe("Entity builder", () => {
} }
) )
expect(user.name).toEqual("user") expect(user.name).toEqual("User")
expect(user.parse().tableName).toEqual("user_table") expect(user.parse().tableName).toEqual("user_table")
const User = toMikroORMEntity(user) const User = toMikroORMEntity(user)
@@ -324,7 +324,7 @@ describe("Entity builder", () => {
} }
) )
expect(user.name).toEqual("userRole") expect(user.name).toEqual("UserRole")
expect(user.parse().tableName).toEqual("user_role") expect(user.parse().tableName).toEqual("user_role")
const User = toMikroORMEntity(user) const User = toMikroORMEntity(user)
@@ -1558,9 +1558,10 @@ describe("Entity builder", () => {
account_id: model.number(), account_id: model.number(),
}) })
const entityBuilder = createMikrORMEntity() const User = toMikroORMEntity(user)
const User = entityBuilder(user) const metaData = MetadataStorage.getMetadataFromDecorator(
const metaData = MetadataStorage.getMetadataFromDecorator(User) User
) as unknown as EntityMetadata<InstanceType<typeof User>>
expect(metaData.properties.id).toEqual({ expect(metaData.properties.id).toEqual({
columnType: "text", columnType: "text",
@@ -3848,7 +3849,7 @@ describe("Entity builder", () => {
}) })
expect(defineEmail).toThrow( expect(defineEmail).toThrow(
'Cannot cascade delete "user" relationship(s) from "email" entity. Child to parent cascades are not allowed' 'Cannot cascade delete "user" relationship(s) from "Email" entity. Child to parent cascades are not allowed'
) )
}) })
@@ -10,9 +10,7 @@ describe("Id property", () => {
fieldName: "id", fieldName: "id",
dataType: { dataType: {
name: "id", name: "id",
options: { options: {},
primaryKey: false,
},
}, },
nullable: false, nullable: false,
indexes: [], indexes: [],
@@ -28,13 +26,12 @@ describe("Id property", () => {
fieldName: "id", fieldName: "id",
dataType: { dataType: {
name: "id", name: "id",
options: { options: {},
primaryKey: true,
},
}, },
nullable: false, nullable: false,
indexes: [], indexes: [],
relationships: [], relationships: [],
primaryKey: true,
}) })
}) })
}) })
@@ -10,9 +10,7 @@ describe("Number property", () => {
fieldName: "age", fieldName: "age",
dataType: { dataType: {
name: "number", name: "number",
options: { options: {},
primaryKey: false,
},
}, },
nullable: false, nullable: false,
indexes: [], indexes: [],
@@ -10,7 +10,7 @@ describe("Text property", () => {
fieldName: "username", fieldName: "username",
dataType: { dataType: {
name: "text", name: "text",
options: { primaryKey: false, searchable: false }, options: { searchable: false },
}, },
nullable: false, nullable: false,
indexes: [], indexes: [],
@@ -26,11 +26,12 @@ describe("Text property", () => {
fieldName: "username", fieldName: "username",
dataType: { dataType: {
name: "text", name: "text",
options: { primaryKey: true, searchable: false }, options: { searchable: false },
}, },
nullable: false, nullable: false,
indexes: [], indexes: [],
relationships: [], relationships: [],
primaryKey: true,
}) })
}) })
}) })
+25 -9
View File
@@ -1,7 +1,17 @@
import type { DMLSchema, RelationshipOptions } from "@medusajs/types" import {
DMLSchema,
IDmlEntityConfig,
RelationshipOptions,
} from "@medusajs/types"
import { DmlEntity } from "./entity" import { DmlEntity } from "./entity"
import { createBigNumberProperties } from "./helpers/entity-builder/create-big-number-properties" import {
import { createDefaultProperties } from "./helpers/entity-builder/create-default-properties" createBigNumberProperties,
DMLSchemaWithBigNumber,
} from "./helpers/entity-builder/create-big-number-properties"
import {
createDefaultProperties,
DMLSchemaDefaults,
} from "./helpers/entity-builder/create-default-properties"
import { ArrayProperty } from "./properties/array" import { ArrayProperty } from "./properties/array"
import { BigNumberProperty } from "./properties/big-number" import { BigNumberProperty } from "./properties/big-number"
import { BooleanProperty } from "./properties/boolean" import { BooleanProperty } from "./properties/boolean"
@@ -57,7 +67,7 @@ export type ManyToManyOptions = RelationshipOptions &
* representing the pivot table created in the * representing the pivot table created in the
* database for this relationship. * database for this relationship.
*/ */
pivotEntity?: () => DmlEntity<any> pivotEntity?: () => DmlEntity<any, any>
} }
) )
@@ -99,17 +109,23 @@ export class EntityBuilder {
* *
* export default MyCustom * export default MyCustom
*/ */
define<Schema extends DMLSchema>( define<Schema extends DMLSchema, TConfig extends IDmlEntityConfig>(
nameOrConfig: DefineOptions, nameOrConfig: TConfig,
schema: Schema schema: Schema
) { ): DmlEntity<
Schema & DMLSchemaWithBigNumber<Schema> & DMLSchemaDefaults,
TConfig
> {
this.#disallowImplicitProperties(schema) this.#disallowImplicitProperties(schema)
return new DmlEntity(nameOrConfig, { return new DmlEntity<Schema, TConfig>(nameOrConfig, {
...schema, ...schema,
...createBigNumberProperties(schema), ...createBigNumberProperties(schema),
...createDefaultProperties(), ...createDefaultProperties(),
}) }) as unknown as DmlEntity<
Schema & DMLSchemaWithBigNumber<Schema> & DMLSchemaDefaults,
TConfig
>
} }
/** /**
+26 -11
View File
@@ -4,25 +4,32 @@ import {
EntityIndex, EntityIndex,
ExtractEntityRelations, ExtractEntityRelations,
IDmlEntity, IDmlEntity,
IDmlEntityConfig,
InferDmlEntityNameFromConfig,
IsDmlEntity, IsDmlEntity,
QueryCondition, QueryCondition,
} from "@medusajs/types" } from "@medusajs/types"
import { isObject, isString, toCamelCase } from "../common" import { isObject, isString, toCamelCase, upperCaseFirst } from "../common"
import { transformIndexWhere } from "./helpers/entity-builder/build-indexes" import { transformIndexWhere } from "./helpers/entity-builder/build-indexes"
import { BelongsTo } from "./relations/belongs-to" import { BelongsTo } from "./relations/belongs-to"
type Config = string | { name?: string; tableName: string } function extractNameAndTableName<Config extends IDmlEntityConfig>(
nameOrConfig: Config
function extractNameAndTableName(nameOrConfig: Config) { ) {
const result = { const result = {
name: "", name: "",
tableName: "", tableName: "",
} as {
name: InferDmlEntityNameFromConfig<Config>
tableName: string
} }
if (isString(nameOrConfig)) { if (isString(nameOrConfig)) {
const [schema, ...rest] = nameOrConfig.split(".") const [schema, ...rest] = nameOrConfig.split(".")
const name = rest.length ? rest.join(".") : schema const name = rest.length ? rest.join(".") : schema
result.name = toCamelCase(name) result.name = upperCaseFirst(
toCamelCase(name)
) as InferDmlEntityNameFromConfig<Config>
result.tableName = nameOrConfig result.tableName = nameOrConfig
} }
@@ -37,7 +44,9 @@ function extractNameAndTableName(nameOrConfig: Config) {
const [schema, ...rest] = potentialName.split(".") const [schema, ...rest] = potentialName.split(".")
const name = rest.length ? rest.join(".") : schema const name = rest.length ? rest.join(".") : schema
result.name = toCamelCase(name) result.name = upperCaseFirst(
toCamelCase(name)
) as InferDmlEntityNameFromConfig<Config>
result.tableName = nameOrConfig.tableName result.tableName = nameOrConfig.tableName
} }
@@ -48,17 +57,23 @@ function extractNameAndTableName(nameOrConfig: Config) {
* Dml entity is a representation of a DML model with a unique * Dml entity is a representation of a DML model with a unique
* name, its schema and relationships. * name, its schema and relationships.
*/ */
export class DmlEntity<Schema extends DMLSchema> implements IDmlEntity<Schema> { export class DmlEntity<
Schema extends DMLSchema,
TConfig extends IDmlEntityConfig
> implements IDmlEntity<Schema, TConfig>
{
[IsDmlEntity]: true = true [IsDmlEntity]: true = true
name: string name: InferDmlEntityNameFromConfig<TConfig>
schema: Schema
readonly #tableName: string readonly #tableName: string
#cascades: EntityCascades<string[]> = {} #cascades: EntityCascades<string[]> = {}
#indexes: EntityIndex<Schema>[] = [] #indexes: EntityIndex<Schema>[] = []
constructor(nameOrConfig: Config, public schema: Schema) { constructor(nameOrConfig: TConfig, schema: Schema) {
const { name, tableName } = extractNameAndTableName(nameOrConfig) const { name, tableName } = extractNameAndTableName(nameOrConfig)
this.schema = schema
this.name = name this.name = name
this.#tableName = tableName this.#tableName = tableName
} }
@@ -70,7 +85,7 @@ export class DmlEntity<Schema extends DMLSchema> implements IDmlEntity<Schema> {
* *
* @param entity * @param entity
*/ */
static isDmlEntity(entity: unknown): entity is DmlEntity<any> { static isDmlEntity(entity: unknown): entity is DmlEntity<any, any> {
return !!entity?.[IsDmlEntity] return !!entity?.[IsDmlEntity]
} }
@@ -78,7 +93,7 @@ export class DmlEntity<Schema extends DMLSchema> implements IDmlEntity<Schema> {
* Parse entity to get its underlying information * Parse entity to get its underlying information
*/ */
parse(): { parse(): {
name: string name: InferDmlEntityNameFromConfig<TConfig>
tableName: string tableName: string
schema: DMLSchema schema: DMLSchema
cascades: EntityCascades<string[]> cascades: EntityCascades<string[]>
@@ -1,4 +1,10 @@
import type { EntityConstructor, Infer } from "@medusajs/types" import type {
DMLSchema,
EntityConstructor,
IDmlEntity,
Infer,
PropertyType,
} from "@medusajs/types"
import { Entity, Filter } from "@mikro-orm/core" import { Entity, Filter } from "@mikro-orm/core"
import { mikroOrmSoftDeletableFilterOptions } from "../../dal" import { mikroOrmSoftDeletableFilterOptions } from "../../dal"
import { DmlEntity } from "../entity" import { DmlEntity } from "../entity"
@@ -34,7 +40,9 @@ export function createMikrORMEntity() {
* A helper function to define a Mikro ORM entity from a * A helper function to define a Mikro ORM entity from a
* DML entity. * DML entity.
*/ */
return function createEntity<T extends DmlEntity<any>>(entity: T): Infer<T> { return function createEntity<T extends DmlEntity<any, any>>(
entity: T
): Infer<T> {
class MikroORMEntity {} class MikroORMEntity {}
const { schema, cascades, indexes: entityIndexes = [] } = entity.parse() const { schema, cascades, indexes: entityIndexes = [] } = entity.parse()
@@ -57,11 +65,11 @@ export function createMikrORMEntity() {
/** /**
* Processing schema fields * Processing schema fields
*/ */
Object.entries(schema).forEach(([name, property]) => { Object.entries(schema as DMLSchema).forEach(([name, property]) => {
const field = property.parse(name) const field = property.parse(name)
if ("fieldName" in field) { if ("fieldName" in field) {
defineProperty(MikroORMEntity, field) defineProperty(MikroORMEntity, name, property as PropertyType<any>)
applyIndexes(MikroORMEntity, tableName, field) applyIndexes(MikroORMEntity, tableName, field)
applySearchable(MikroORMEntity, field) applySearchable(MikroORMEntity, field)
} else { } else {
@@ -85,14 +93,16 @@ export function createMikrORMEntity() {
* return the input idempotently * return the input idempotently
* @param entity * @param entity
*/ */
export const toMikroORMEntity = <T>(entity: T): Infer<T> => { export const toMikroORMEntity = <T>(
entity: T
): T extends IDmlEntity<any, any> ? Infer<T> : T => {
let mikroOrmEntity: T | EntityConstructor<any> = entity let mikroOrmEntity: T | EntityConstructor<any> = entity
if (DmlEntity.isDmlEntity(entity)) { if (DmlEntity.isDmlEntity(entity)) {
mikroOrmEntity = createMikrORMEntity()(entity) mikroOrmEntity = createMikrORMEntity()(entity)
} }
return mikroOrmEntity as Infer<T> return mikroOrmEntity as T extends IDmlEntity<any, any> ? Infer<T> : T
} }
/** /**
@@ -110,6 +120,6 @@ export const toMikroOrmEntities = function <T extends any[]>(entities: T) {
return entity return entity
}) as { }) as {
[K in keyof T]: T[K] extends DmlEntity<any> ? Infer<T[K]> : T[K] [K in keyof T]: T[K] extends IDmlEntity<any, any> ? Infer<T[K]> : T[K]
} }
} }
@@ -13,7 +13,7 @@ import { NullableModifier } from "../../properties/nullable"
* test.amount // valid | type = number * test.amount // valid | type = number
* test.raw_amount // valid | type = Record<string, any> * test.raw_amount // valid | type = Record<string, any>
*/ */
type DMLSchemaWithBigNumber<T extends DMLSchema> = { export type DMLSchemaWithBigNumber<T extends DMLSchema> = {
[K in keyof T]: T[K] [K in keyof T]: T[K]
} & { } & {
[K in keyof T as T[K] extends [K in keyof T as T[K] extends
@@ -2,6 +2,7 @@ import {
EntityConstructor, EntityConstructor,
KnownDataTypes, KnownDataTypes,
PropertyMetadata, PropertyMetadata,
PropertyType,
} from "@medusajs/types" } from "@medusajs/types"
import { MikroOrmBigNumberProperty } from "../../../dal" import { MikroOrmBigNumberProperty } from "../../../dal"
import { generateEntityId, isDefined } from "../../../common" import { generateEntityId, isDefined } from "../../../common"
@@ -14,6 +15,7 @@ import {
Property, Property,
Utils, Utils,
} from "@mikro-orm/core" } from "@mikro-orm/core"
import { PrimaryKeyModifier } from "../../properties/primary-key"
/** /**
* DML entity data types to PostgreSQL data types via * DML entity data types to PostgreSQL data types via
@@ -91,8 +93,10 @@ const SPECIAL_PROPERTIES: {
*/ */
export function defineProperty( export function defineProperty(
MikroORMEntity: EntityConstructor<any>, MikroORMEntity: EntityConstructor<any>,
field: PropertyMetadata propertyName: string,
property: PropertyType<any>
) { ) {
const field = property.parse(propertyName)
/** /**
* Here we initialize nullable properties with a null value * Here we initialize nullable properties with a null value
*/ */
@@ -169,7 +173,7 @@ export function defineProperty(
* Defining an id property * Defining an id property
*/ */
if (field.dataType.name === "id") { if (field.dataType.name === "id") {
const IdDecorator = field.dataType.options?.primaryKey const IdDecorator = PrimaryKeyModifier.isPrimaryKeyModifier(property)
? PrimaryKey({ ? PrimaryKey({
columnType: "text", columnType: "text",
type: "string", type: "string",
@@ -211,7 +215,7 @@ export function defineProperty(
/** /**
* Defining a primary key property * Defining a primary key property
*/ */
if (field.dataType.options?.primaryKey) { if (PrimaryKeyModifier.isPrimaryKeyModifier(property)) {
PrimaryKey({ PrimaryKey({
columnType, columnType,
type: propertyType, type: propertyType,
@@ -9,9 +9,9 @@ import {
BeforeCreate, BeforeCreate,
ManyToMany, ManyToMany,
ManyToOne, ManyToOne,
OnInit,
OneToMany, OneToMany,
OneToOne, OneToOne,
OnInit,
Property, Property,
} from "@mikro-orm/core" } from "@mikro-orm/core"
import { camelToSnakeCase, pluralize } from "../../../common" import { camelToSnakeCase, pluralize } from "../../../common"
@@ -81,7 +81,8 @@ export function defineBelongsToRelationship(
MikroORMEntity: EntityConstructor<any>, MikroORMEntity: EntityConstructor<any>,
relationship: RelationshipMetadata, relationship: RelationshipMetadata,
relatedEntity: DmlEntity< relatedEntity: DmlEntity<
Record<string, PropertyType<any> | RelationshipType<any>> Record<string, PropertyType<any> | RelationshipType<any>>,
any
>, >,
{ relatedModelName }: { relatedModelName: string } { relatedModelName }: { relatedModelName: string }
) { ) {
@@ -213,7 +214,8 @@ export function defineManyToManyRelationship(
MikroORMEntity: EntityConstructor<any>, MikroORMEntity: EntityConstructor<any>,
relationship: RelationshipMetadata, relationship: RelationshipMetadata,
relatedEntity: DmlEntity< relatedEntity: DmlEntity<
Record<string, PropertyType<any> | RelationshipType<any>> Record<string, PropertyType<any> | RelationshipType<any>>,
any
>, >,
{ {
relatedModelName, relatedModelName,
@@ -5,7 +5,7 @@ import { camelToSnakeCase, toCamelCase, upperCaseFirst } from "../../../common"
* Parses entity name and returns model and table name from * Parses entity name and returns model and table name from
* it * it
*/ */
export function parseEntityName(entity: DmlEntity<any>) { export function parseEntityName(entity: DmlEntity<any, any>) {
const parsedEntity = entity.parse() const parsedEntity = entity.parse()
/** /**
+11 -4
View File
@@ -1,19 +1,27 @@
import { BaseProperty } from "./base" import { BaseProperty } from "./base"
import { PrimaryKeyModifier } from "./primary-key"
const IsIdProperty = Symbol("IsIdProperty")
/** /**
* The Id property defines a unique identifier for the schema. * The Id property defines a unique identifier for the schema.
* Most of the times it will be the primary as well. * Most of the times it will be the primary as well.
*/ */
export class IdProperty extends BaseProperty<string> { export class IdProperty extends BaseProperty<string> {
[IsIdProperty] = true
static isIdProperty(value: any): value is IdProperty {
return !!value?.[IsIdProperty]
}
protected dataType: { protected dataType: {
name: "id" name: "id"
options: { options: {
primaryKey: boolean
prefix?: string prefix?: string
} }
} = { } = {
name: "id", name: "id",
options: { primaryKey: false }, options: {},
} }
constructor(options?: { prefix?: string }) { constructor(options?: { prefix?: string }) {
@@ -37,7 +45,6 @@ export class IdProperty extends BaseProperty<string> {
* @customNamespace Property Configuration Methods * @customNamespace Property Configuration Methods
*/ */
primaryKey() { primaryKey() {
this.dataType.options.primaryKey = true return new PrimaryKeyModifier<string, IdProperty>(this)
return this
} }
} }
@@ -1,4 +1,5 @@
import { BaseProperty } from "./base" import { BaseProperty } from "./base"
import { PrimaryKeyModifier } from "./primary-key"
/** /**
* The NumberProperty is used to define a numeric/integer * The NumberProperty is used to define a numeric/integer
@@ -7,15 +8,11 @@ import { BaseProperty } from "./base"
export class NumberProperty extends BaseProperty<number> { export class NumberProperty extends BaseProperty<number> {
protected dataType: { protected dataType: {
name: "number" name: "number"
options: { options: {}
primaryKey: boolean
}
} }
primaryKey() { primaryKey() {
this.dataType.options.primaryKey = true return new PrimaryKeyModifier<number, NumberProperty>(this)
return this
} }
constructor(options?: { primaryKey?: boolean }) { constructor(options?: { primaryKey?: boolean }) {
@@ -23,7 +20,7 @@ export class NumberProperty extends BaseProperty<number> {
this.dataType = { this.dataType = {
name: "number", name: "number",
options: { primaryKey: false, ...options }, options: { ...options },
} }
} }
} }
@@ -0,0 +1,39 @@
import { PropertyType } from "@medusajs/types"
const IsPrimaryKeyModifier = Symbol.for("isPrimaryKeyModifier")
/**
* PrimaryKey modifier marks a schema node as primaryKey
*/
export class PrimaryKeyModifier<T, Schema extends PropertyType<T>>
implements PropertyType<T>
{
[IsPrimaryKeyModifier]: true = true
static isPrimaryKeyModifier(obj: any): obj is PrimaryKeyModifier<any, any> {
return !!obj?.[IsPrimaryKeyModifier]
}
/**
* A type-only property to infer the JavScript data-type
* of the schema property
*/
declare $dataType: T
/**
* The parent schema on which the primaryKey modifier is
* applied
*/
#schema: Schema
constructor(schema: Schema) {
this.#schema = schema
}
/**
* Returns the serialized metadata
*/
parse(fieldName: string) {
const schema = this.#schema.parse(fieldName)
schema.primaryKey = true
return schema
}
}
@@ -1,4 +1,5 @@
import { BaseProperty } from "./base" import { BaseProperty } from "./base"
import { PrimaryKeyModifier } from "./primary-key"
/** /**
* The TextProperty is used to define a textual property * The TextProperty is used to define a textual property
@@ -7,14 +8,12 @@ export class TextProperty extends BaseProperty<string> {
protected dataType: { protected dataType: {
name: "text" name: "text"
options: { options: {
primaryKey: boolean
prefix?: string prefix?: string
searchable: boolean searchable: boolean
} }
} = { } = {
name: "text", name: "text",
options: { options: {
primaryKey: false,
searchable: false, searchable: false,
}, },
} }
@@ -35,9 +34,7 @@ export class TextProperty extends BaseProperty<string> {
* @customNamespace Property Configuration Methods * @customNamespace Property Configuration Methods
*/ */
primaryKey() { primaryKey() {
this.dataType.options.primaryKey = true return new PrimaryKeyModifier<string, TextProperty>(this)
return this
} }
/** /**
@@ -5,11 +5,15 @@ import {
RelationshipTypes, RelationshipTypes,
} from "@medusajs/types" } from "@medusajs/types"
export const IsRelationship = Symbol.for("isRelationship")
/** /**
* The BaseRelationship encapsulates the repetitive parts of defining * The BaseRelationship encapsulates the repetitive parts of defining
* a relationship * a relationship
*/ */
export abstract class BaseRelationship<T> implements RelationshipType<T> { export abstract class BaseRelationship<T> implements RelationshipType<T> {
[IsRelationship]: true = true
#referencedEntity: T #referencedEntity: T
/** /**
@@ -28,6 +32,12 @@ export abstract class BaseRelationship<T> implements RelationshipType<T> {
*/ */
declare $dataType: T declare $dataType: T
static isRelationship<T>(
relationship: any
): relationship is BaseRelationship<T> {
return !!relationship?.[IsRelationship]
}
constructor(referencedEntity: T, options: RelationshipOptions) { constructor(referencedEntity: T, options: RelationshipOptions) {
this.#referencedEntity = referencedEntity this.#referencedEntity = referencedEntity
this.options = options this.options = options
@@ -1,4 +1,5 @@
import { RelationshipType } from "@medusajs/types" import { RelationshipType } from "@medusajs/types"
import { IsRelationship } from "./base"
const IsNullableModifier = Symbol.for("isNullableModifier") const IsNullableModifier = Symbol.for("isNullableModifier")
@@ -8,7 +9,8 @@ const IsNullableModifier = Symbol.for("isNullableModifier")
export class NullableModifier<T, Relation extends RelationshipType<T>> export class NullableModifier<T, Relation extends RelationshipType<T>>
implements RelationshipType<T | null> implements RelationshipType<T | null>
{ {
[IsNullableModifier]: true = true [IsNullableModifier]: true = true;
[IsRelationship]: true = true
static isNullableModifier<T>( static isNullableModifier<T>(
modifier: any modifier: any
@@ -0,0 +1,53 @@
import { model } from "../../../dml"
export const FulfillmentSet = {
name: "FulfillmentSet",
}
export const ShippingOption = {
name: "ShippingOption",
}
export const ShippingProfile = {
name: "ShippingProfile",
}
export const Fulfillment = {
name: "Fulfillment",
}
export const FulfillmentProvider = {
name: "FulfillmentProvider",
}
export const ServiceZone = {
name: "ServiceZone",
}
export const GeoZone = {
name: "GeoZone",
}
export const ShippingOptionRule = {
name: "ShippingOptionRule",
}
export const dmlFulfillmentSet = model.define(FulfillmentSet.name, {
id: model.id().primaryKey(),
})
export const dmlShippingOption = model.define(ShippingOption.name, {
id: model.id().primaryKey(),
})
export const dmlShippingProfile = model.define(ShippingProfile.name, {
id: model.id().primaryKey(),
})
export const dmlFulfillment = model.define(Fulfillment.name, {
id: model.id().primaryKey(),
})
export const dmlFulfillmentProvider = model.define(FulfillmentProvider.name, {
id: model.id().primaryKey(),
})
export const dmlServiceZone = model.define(ServiceZone.name, {
id: model.id().primaryKey(),
})
export const dmlGeoZone = model.define(GeoZone.name, {
id: model.id().primaryKey(),
})
export const dmlShippingOptionRule = model.define(ShippingOptionRule.name, {
id: model.id().primaryKey(),
})
@@ -1,35 +1,36 @@
import { defineJoinerConfig } from "../joiner-config-builder" import {
buildLinkableKeysFromDmlObjects,
buildLinkableKeysFromMikroOrmObjects,
buildLinkConfigFromDmlObjects,
defineJoinerConfig,
} from "../joiner-config-builder"
import { Modules } from "../definition" import { Modules } from "../definition"
import { model } from "../../dml"
import { expectTypeOf } from "expect-type"
import {
dmlFulfillment,
dmlFulfillmentProvider,
dmlFulfillmentSet,
dmlGeoZone,
dmlServiceZone,
dmlShippingOption,
dmlShippingOptionRule,
dmlShippingProfile,
Fulfillment,
FulfillmentProvider,
FulfillmentSet,
GeoZone,
ServiceZone,
ShippingOption,
ShippingOptionRule,
ShippingProfile,
} from "../__fixtures__/joiner-config/entities"
const FulfillmentSet = { describe("joiner-config-builder", () => {
name: "FulfillmentSet", describe("defineJoiner | Mikro orm objects", () => {
}
const ShippingOption = {
name: "ShippingOption",
}
const ShippingProfile = {
name: "ShippingProfile",
}
const Fulfillment = {
name: "Fulfillment",
}
const FulfillmentProvider = {
name: "FulfillmentProvider",
}
const ServiceZone = {
name: "ServiceZone",
}
const GeoZone = {
name: "GeoZone",
}
const ShippingOptionRule = {
name: "ShippingOptionRule",
}
describe("defineJoiner", () => {
it("should return a full joiner configuration", () => { it("should return a full joiner configuration", () => {
const joinerConfig = defineJoinerConfig(Modules.FULFILLMENT, { const joinerConfig = defineJoinerConfig(Modules.FULFILLMENT, {
entityQueryingConfig: [ models: [
FulfillmentSet, FulfillmentSet,
ShippingOption, ShippingOption,
ShippingProfile, ShippingProfile,
@@ -148,7 +149,7 @@ describe("defineJoiner", () => {
it("should return a full joiner configuration with custom aliases and models", () => { it("should return a full joiner configuration with custom aliases and models", () => {
const joinerConfig = defineJoinerConfig(Modules.FULFILLMENT, { const joinerConfig = defineJoinerConfig(Modules.FULFILLMENT, {
entityQueryingConfig: [ models: [
FulfillmentSet, FulfillmentSet,
ShippingOption, ShippingOption,
ShippingProfile, ShippingProfile,
@@ -282,7 +283,7 @@ describe("defineJoiner", () => {
it("should return a full joiner configuration with custom aliases overriding defaults", () => { it("should return a full joiner configuration with custom aliases overriding defaults", () => {
const joinerConfig = defineJoinerConfig(Modules.FULFILLMENT, { const joinerConfig = defineJoinerConfig(Modules.FULFILLMENT, {
entityQueryingConfig: [FulfillmentSet], models: [FulfillmentSet],
alias: [ alias: [
{ {
name: ["fulfillment_set", "fulfillment_sets"], name: ["fulfillment_set", "fulfillment_sets"],
@@ -312,4 +313,193 @@ describe("defineJoiner", () => {
], ],
}) })
}) })
})
describe("defineJoiner | DML objects", () => {
it("should return a full joiner configuration", () => {
const joinerConfig = defineJoinerConfig(Modules.FULFILLMENT, {
models: [
dmlFulfillmentSet,
dmlShippingOption,
dmlShippingProfile,
dmlFulfillment,
dmlFulfillmentProvider,
dmlServiceZone,
dmlGeoZone,
dmlShippingOptionRule,
],
})
expect(joinerConfig).toEqual({
serviceName: Modules.FULFILLMENT,
primaryKeys: ["id"],
schema: undefined,
linkableKeys: {
fulfillment_set_id: FulfillmentSet.name,
shipping_option_id: ShippingOption.name,
shipping_profile_id: ShippingProfile.name,
fulfillment_id: Fulfillment.name,
fulfillment_provider_id: FulfillmentProvider.name,
service_zone_id: ServiceZone.name,
geo_zone_id: GeoZone.name,
shipping_option_rule_id: ShippingOptionRule.name,
},
alias: [
{
name: ["fulfillment_set", "fulfillment_sets"],
args: {
entity: FulfillmentSet.name,
methodSuffix: "FulfillmentSets",
},
},
{
name: ["shipping_option", "shipping_options"],
args: {
entity: ShippingOption.name,
methodSuffix: "ShippingOptions",
},
},
{
name: ["shipping_profile", "shipping_profiles"],
args: {
entity: ShippingProfile.name,
methodSuffix: "ShippingProfiles",
},
},
{
name: ["fulfillment", "fulfillments"],
args: {
entity: Fulfillment.name,
methodSuffix: "Fulfillments",
},
},
{
name: ["fulfillment_provider", "fulfillment_providers"],
args: {
entity: FulfillmentProvider.name,
methodSuffix: "FulfillmentProviders",
},
},
{
name: ["service_zone", "service_zones"],
args: {
entity: ServiceZone.name,
methodSuffix: "ServiceZones",
},
},
{
name: ["geo_zone", "geo_zones"],
args: {
entity: GeoZone.name,
methodSuffix: "GeoZones",
},
},
{
name: ["shipping_option_rule", "shipping_option_rules"],
args: {
entity: ShippingOptionRule.name,
methodSuffix: "ShippingOptionRules",
},
},
],
})
})
})
describe("buildLinkableKeysFromDmlObjects", () => {
it("should return a linkableKeys object based on the DML's primary keys", () => {
const user = model.define("user", {
id: model.id().primaryKey(),
name: model.text(),
})
const car = model.define("car", {
id: model.id(),
number_plate: model.text().primaryKey(),
test: model.text(),
})
const linkableKeys = buildLinkableKeysFromDmlObjects([user, car])
expectTypeOf(linkableKeys).toMatchTypeOf<{
user_id: "User"
car_number_plate: "Car"
}>()
expect(linkableKeys).toEqual({
user_id: user.name,
car_number_plate: car.name,
})
})
})
describe("buildLinkableKeysFromMikroOrmObjects", () => {
it("should return a linkableKeys object based on the mikro orm models name", () => {
class User {}
class Car {}
const linkableKeys = buildLinkableKeysFromMikroOrmObjects([Car, User])
expect(linkableKeys).toEqual({
user_id: User.name,
car_id: Car.name,
})
})
})
describe("buildLinkConfigFromDmlObjects", () => {
it("should return a link config object based on the DML's primary keys", () => {
const user = model.define("user", {
id: model.id().primaryKey(),
name: model.text(),
})
const car = model.define("car", {
id: model.id(),
number_plate: model.text().primaryKey(),
})
const linkConfig = buildLinkConfigFromDmlObjects([user, car])
expectTypeOf(linkConfig).toMatchTypeOf<{
user: {
id: {
linkable: "user_id"
primaryKey: "id"
}
toJSON: () => {
linkable: string
primaryKey: string
}
}
car: {
number_plate: {
linkable: "car_number_plate"
primaryKey: "number_plate"
}
toJSON: () => {
linkable: string
primaryKey: string
}
}
}>()
expect(linkConfig.user.id).toEqual({
linkable: "user_id",
primaryKey: "id",
})
expect(linkConfig.car.number_plate).toEqual({
linkable: "car_number_plate",
primaryKey: "number_plate",
})
expect(linkConfig.car.toJSON()).toEqual({
linkable: "car_number_plate",
primaryKey: "number_plate",
})
expect(linkConfig.user.toJSON()).toEqual({
linkable: "user_id",
primaryKey: "id",
})
})
})
}) })
@@ -1,6 +1,9 @@
import { Context, EventBusTypes } from "@medusajs/types" import { Context, EventBusTypes } from "@medusajs/types"
// TODO should that move closer to the event bus? and maybe be rename to moduleEventBuilderFactory
/** /**
*
* Factory function to create event builders for different entities * Factory function to create event builders for different entities
* *
* @example * @example
@@ -48,7 +51,8 @@ export function eventBuilderFactory({
// The event enums contains event formatted like so [object]_[action] e.g. PRODUCT_CREATED // The event enums contains event formatted like so [object]_[action] e.g. PRODUCT_CREATED
// We expect the keys of events to be fully uppercased // We expect the keys of events to be fully uppercased
const eventName = eventsEnum[`${object.toUpperCase()}_${action.toUpperCase()}`] const eventName =
eventsEnum[`${object.toUpperCase()}_${action.toUpperCase()}`]
data.forEach((dataItem) => { data.forEach((dataItem) => {
messages.push({ messages.push({
+1 -1
View File
@@ -13,4 +13,4 @@ export * from "./medusa-internal-service"
export * from "./medusa-service" export * from "./medusa-service"
export * from "./migration-scripts" export * from "./migration-scripts"
export * from "./mikro-orm-cli-config-builder" export * from "./mikro-orm-cli-config-builder"
export * from "./module"
@@ -1,14 +1,24 @@
import { JoinerServiceConfigAlias, ModuleJoinerConfig } from "@medusajs/types" import {
JoinerServiceConfigAlias,
ModuleJoinerConfig,
PropertyType,
} from "@medusajs/types"
import { dirname, join } from "path" import { dirname, join } from "path"
import { import {
MapToConfig,
camelToSnakeCase, camelToSnakeCase,
deduplicate, deduplicate,
getCallerFilePath, getCallerFilePath,
isObject,
lowerCaseFirst,
MapToConfig,
pluralize, pluralize,
upperCaseFirst, upperCaseFirst,
} from "../common" } from "../common"
import { loadModels } from "./loaders/load-models" import { loadModels } from "./loaders/load-models"
import { DmlEntity } from "../dml"
import { BaseRelationship } from "../dml/relations/base"
import { PrimaryKeyModifier } from "../dml/properties/primary-key"
import { InferLinkableKeys, InfersLinksConfig } from "./types/links-config"
/** /**
* Define joiner config for a module based on the models (object representation or entities) present in the models directory. This action will be sync until * Define joiner config for a module based on the models (object representation or entities) present in the models directory. This action will be sync until
@@ -20,7 +30,7 @@ import { loadModels } from "./loaders/load-models"
* @param moduleName * @param moduleName
* @param alias * @param alias
* @param schema * @param schema
* @param entityQueryingConfig * @param models
* @param linkableKeys * @param linkableKeys
* @param primaryKeys * @param primaryKeys
*/ */
@@ -29,13 +39,13 @@ export function defineJoinerConfig(
{ {
alias, alias,
schema, schema,
entityQueryingConfig, models,
linkableKeys, linkableKeys,
primaryKeys, primaryKeys,
}: { }: {
alias?: JoinerServiceConfigAlias[] alias?: JoinerServiceConfigAlias[]
schema?: string schema?: string
entityQueryingConfig?: { name: string }[] models?: DmlEntity<any, any>[] | { name: string }[]
linkableKeys?: Record<string, string> linkableKeys?: Record<string, string>
primaryKeys?: string[] primaryKeys?: string[]
} = {} } = {}
@@ -62,20 +72,64 @@ export function defineJoinerConfig(
basePath = join(basePath, "models") basePath = join(basePath, "models")
const models = deduplicate( let loadedModels = models ?? loadModels(basePath)
[...(entityQueryingConfig ?? loadModels(basePath))].flatMap((v) => v!.name) const modelDefinitions = new Map(
).map((name) => ({ name })) loadedModels
.filter((model) => !!DmlEntity.isDmlEntity(model))
.map((model) => [model.name, model])
)
const mikroOrmObjects = new Map(
loadedModels
.filter((model) => !DmlEntity.isDmlEntity(model))
.map((model) => [model.name, model])
)
// We prioritize DML if there is any equivalent Mikro orm entities found
loadedModels = [...modelDefinitions.values()]
mikroOrmObjects.forEach((model) => {
if (modelDefinitions.has(model.name)) {
return
}
loadedModels.push(model)
})
if (!linkableKeys) {
const linkableKeysFromDml = buildLinkableKeysFromDmlObjects([
...modelDefinitions.values(),
])
const linkableKeysFromMikroOrm = buildLinkableKeysFromMikroOrmObjects([
...mikroOrmObjects.values(),
])
linkableKeys = {
...linkableKeysFromDml,
...linkableKeysFromMikroOrm,
}
}
if (!primaryKeys && modelDefinitions.size) {
const linkConfig = buildLinkConfigFromDmlObjects([
...modelDefinitions.values(),
])
primaryKeys = deduplicate(
Object.values(linkConfig).flatMap((entityLinkConfig) => {
return (Object.values(entityLinkConfig) as any[])
.filter((linkableConfig) => isObject(linkableConfig))
.map((linkableConfig) => {
return linkableConfig.primaryKey
})
})
)
}
// 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: moduleName,
primaryKeys: primaryKeys ?? ["id"], primaryKeys: primaryKeys ?? ["id"],
schema, schema,
linkableKeys: linkableKeys: linkableKeys,
linkableKeys ??
models.reduce((acc, entity) => {
acc[`${camelToSnakeCase(entity.name).toLowerCase()}_id`] = entity.name
return acc
}, {} as Record<string, string>),
alias: [ alias: [
...[...(alias ?? ([] as any))].map((alias) => ({ ...[...(alias ?? ([] as any))].map((alias) => ({
name: alias.name, name: alias.name,
@@ -86,7 +140,7 @@ export function defineJoinerConfig(
pluralize(upperCaseFirst(alias.args.entity)), pluralize(upperCaseFirst(alias.args.entity)),
}, },
})), })),
...models ...loadedModels
.filter((model) => { .filter((model) => {
return ( return (
!alias || !alias.some((alias) => alias.args?.entity === model.name) !alias || !alias.some((alias) => alias.args?.entity === model.name)
@@ -106,8 +160,153 @@ export function defineJoinerConfig(
} }
} }
/**
* From a set of DML objects, build the linkable keys
*
* @example
* const user = model.define("user", {
* id: model.id(),
* name: model.text(),
* })
*
* const car = model.define("car", {
* id: model.id(),
* number_plate: model.text().primaryKey(),
* test: model.text(),
* })
*
* // output:
* // {
* // user_id: 'User',
* // car_number_plate: 'Car',
* // }
*
* @param models
*/
export function buildLinkableKeysFromDmlObjects<
const T extends DmlEntity<any, any>[],
LinkableKeys = InferLinkableKeys<T>
>(models: T): LinkableKeys {
const linkableKeys = {} as LinkableKeys
for (const model of models) {
if (!DmlEntity.isDmlEntity(model)) {
continue
}
const schema = model.schema
const primaryKeys: string[] = []
for (const [property, value] of Object.entries(schema)) {
if (BaseRelationship.isRelationship(value)) {
continue
}
const parsedProperty = (value as PropertyType<any>).parse(property)
if (PrimaryKeyModifier.isPrimaryKeyModifier(value)) {
const linkableKeyName =
parsedProperty.dataType.options?.linkable ??
`${camelToSnakeCase(model.name).toLowerCase()}_${property}`
primaryKeys.push(linkableKeyName)
}
}
if (primaryKeys.length) {
primaryKeys.forEach((primaryKey) => {
linkableKeys[primaryKey] = model.name
})
}
}
return linkableKeys
}
/**
* Build linkable keys from MikroORM objects
* @deprecated
* @param models
*/
export function buildLinkableKeysFromMikroOrmObjects(
models: Function[]
): Record<string, string> {
return models.reduce((acc, entity) => {
acc[`${camelToSnakeCase(entity.name).toLowerCase()}_id`] = entity.name
return acc
}, {}) as Record<string, string>
}
/** /**
* Build entities name to linkable keys map * Build entities name to linkable keys map
*
* @example
* const user = model.define("user", {
* id: model.id(),
* name: model.text(),
* })
*
* const car = model.define("car", {
* id: model.id(),
* number_plate: model.text().primaryKey(),
* test: model.text(),
* })
*
* // output:
* // {
* // toJSON: function () { },
* // user: {
* // id: "user_id",
* // },
* // car: {
* // number_plate: "car_number_plate",
* // },
* // }
*
* @param models
*/
export function buildLinkConfigFromDmlObjects<
const T extends DmlEntity<any, any>[]
>(models: T = [] as unknown as T): InfersLinksConfig<T> {
const linkConfig = {} as InfersLinksConfig<T>
for (const model of models) {
if (!DmlEntity.isDmlEntity(model)) {
continue
}
const schema = model.schema
const modelLinkConfig = (linkConfig[lowerCaseFirst(model.name)] ??= {
toJSON: function () {
const linkables = Object.entries(this)
.filter(([name]) => name !== "toJSON")
.map(([, object]) => object)
const lastIndex = linkables.length - 1
return linkables[lastIndex]
},
})
for (const [property, value] of Object.entries(schema)) {
if (BaseRelationship.isRelationship(value)) {
continue
}
const parsedProperty = (value as PropertyType<any>).parse(property)
if (PrimaryKeyModifier.isPrimaryKeyModifier(value)) {
const linkableKeyName =
parsedProperty.dataType.options?.linkable ??
`${camelToSnakeCase(model.name).toLowerCase()}_${property}`
modelLinkConfig[property] = {
linkable: linkableKeyName,
primaryKey: property,
}
}
}
}
return linkConfig as InfersLinksConfig<T> & Record<any, any>
}
/**
* Reversed map from linkableKeys to entity name to linkable keys
* @param linkableKeys * @param linkableKeys
*/ */
export function buildEntitiesNameToLinkableKeysMap( export function buildEntitiesNameToLinkableKeysMap(
@@ -27,15 +27,15 @@ export function loadModels(basePath: string) {
if (stats.isFile()) { if (stats.isFile()) {
try { try {
const required = require(filePath) as { const required = require(filePath)
[key: string]: { name?: string }
}
return Object.values(required).filter((resource) => !!resource.name) return Object.values(required).filter(
(resource: any) => !!resource.name
)
} catch (e) {} } catch (e) {}
} }
return return
}) })
.filter(Boolean) as { name: string }[] .filter(Boolean) as any[]
} }
@@ -35,12 +35,16 @@ type SelectorAndData = {
data: any data: any
} }
export function MedusaInternalService<TContainer extends object = object>( export function MedusaInternalService<
TContainer extends object = object,
TEntity extends object = any
>(
rawModel: any rawModel: any
): { ): {
new <TEntity extends object = any>( new (container: TContainer): ModulesSdkTypes.IMedusaInternalService<
container: TContainer TEntity,
): ModulesSdkTypes.IMedusaInternalService<TEntity, TContainer> TContainer
>
} { } {
const model = DmlEntity.isDmlEntity(rawModel) const model = DmlEntity.isDmlEntity(rawModel)
? toMikroORMEntity(rawModel) ? toMikroORMEntity(rawModel)
@@ -49,7 +53,7 @@ export function MedusaInternalService<TContainer extends object = object>(
const injectedRepositoryName = `${lowerCaseFirst(model.name)}Repository` const injectedRepositoryName = `${lowerCaseFirst(model.name)}Repository`
const propertyRepositoryName = `__${injectedRepositoryName}__` const propertyRepositoryName = `__${injectedRepositoryName}__`
class AbstractService_<TEntity extends object> class AbstractService_
implements ModulesSdkTypes.IMedusaInternalService<TEntity, TContainer> implements ModulesSdkTypes.IMedusaInternalService<TEntity, TContainer>
{ {
readonly __container__: TContainer; readonly __container__: TContainer;
@@ -556,7 +560,5 @@ export function MedusaInternalService<TContainer extends object = object>(
} }
} }
return AbstractService_ as unknown as new <TEntity extends {}>( return AbstractService_ as any
container: TContainer
) => ModulesSdkTypes.IMedusaInternalService<TEntity, TContainer>
} }
@@ -2,11 +2,10 @@
* Utility factory and interfaces for module service public facing API * Utility factory and interfaces for module service public facing API
*/ */
import { import {
Constructor,
Context, Context,
FindConfig, FindConfig,
IEventBusModuleService, IEventBusModuleService,
Pluralize, ModuleJoinerConfig,
RepositoryService, RepositoryService,
RestoreReturn, RestoreReturn,
SoftDeleteReturn, SoftDeleteReturn,
@@ -22,17 +21,15 @@ import {
} from "../common" } from "../common"
import { InjectManager, MedusaContext } from "./decorators" import { InjectManager, MedusaContext } from "./decorators"
import { ModuleRegistrationName } from "./definition" import { ModuleRegistrationName } from "./definition"
import { DmlEntity } from "../dml" import {
BaseMethods,
type BaseMethods = EntitiesConfigTemplate,
| "retrieve" ExtractKeysFromConfig,
| "list" MedusaServiceReturnType,
| "listAndCount" ModelConfigurationsToConfigTemplate,
| "delete" TEntityEntries,
| "softDelete" } from "./types/medusa-service"
| "restore" import { buildEntitiesNameToLinkableKeysMap } from "./joiner-config-builder"
| "create"
| "update"
const readMethods = ["retrieve", "list", "listAndCount"] as BaseMethods[] const readMethods = ["retrieve", "list", "listAndCount"] as BaseMethods[]
const writeMethods = [ const writeMethods = [
@@ -45,200 +42,6 @@ const writeMethods = [
const methods: BaseMethods[] = [...readMethods, ...writeMethods] const methods: BaseMethods[] = [...readMethods, ...writeMethods]
type ModelDTOConfig = {
dto: object
create?: any
update?: any
/**
* @internal
* @deprecated
*/
singular?: string
/**
* @internal
* @deprecated
*/
plural?: string
}
type EntitiesConfigTemplate = { [key: string]: ModelDTOConfig }
type ModelConfigurationsToConfigTemplate<T extends TEntityEntries> = {
[Key in keyof T as `${Capitalize<Key & string>}`]: {
dto: T[Key] extends Constructor<any> ? InstanceType<T[Key]> : any
create: any
update: any
singular: T[Key] extends { singular: string } ? T[Key]["singular"] : Key
plural: T[Key] extends { plural: string }
? T[Key]["plural"]
: Pluralize<Key & string>
}
}
/**
* @deprecated should all notion of singular and plural be removed once all modules are aligned with the convention
*/
type ExtractSingularName<T extends Record<any, any>, K = keyof T> = Capitalize<
T[K] extends { singular?: string } ? T[K]["singular"] & string : K & string
>
/**
* @deprecated should all notion of singular and plural be removed once all modules are aligned with the convention
* The pluralize will move to where it should be used instead
*/
type ExtractPluralName<T extends Record<any, any>, K = keyof T> = Capitalize<
T[K] extends {
plural?: string
}
? T[K]["plural"] & string
: Pluralize<K & string>
>
// TODO: The future expected entry will be a DML object but in the meantime we have to maintain backward compatibility for ouw own modules and therefore we need to support Constructor<any> as well as this temporary object
type TEntityEntries<Keys = string> = Record<
Keys & string,
| Constructor<any>
| DmlEntity<any>
| { name?: string; singular?: string; plural?: string }
>
type ExtractKeysFromConfig<EntitiesConfig> = EntitiesConfig extends {
__empty: any
}
? string
: keyof EntitiesConfig
export type AbstractModuleService<
TEntitiesDtoConfig extends Record<string, any>
> = {
[TEntityName in keyof TEntitiesDtoConfig as `retrieve${ExtractSingularName<
TEntitiesDtoConfig,
TEntityName
>}`]: (
id: string,
config?: FindConfig<any>,
sharedContext?: Context
) => Promise<TEntitiesDtoConfig[TEntityName]["dto"]>
} & {
[TEntityName in keyof TEntitiesDtoConfig as `list${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: (
filters?: any,
config?: FindConfig<any>,
sharedContext?: Context
) => Promise<TEntitiesDtoConfig[TEntityName]["dto"][]>
} & {
[TEntityName in keyof TEntitiesDtoConfig as `listAndCount${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(filters?: any, config?: FindConfig<any>, sharedContext?: Context): Promise<
[TEntitiesDtoConfig[TEntityName]["dto"][], number]
>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `delete${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(
primaryKeyValues: string | object | string[] | object[],
sharedContext?: Context
): Promise<void>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `softDelete${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
<TReturnableLinkableKeys extends string>(
primaryKeyValues: string | object | string[] | object[],
config?: SoftDeleteReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `restore${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
<TReturnableLinkableKeys extends string>(
primaryKeyValues: string | object | string[] | object[],
config?: RestoreReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `create${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(...args: any[]): Promise<any>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `update${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(...args: any[]): Promise<any>
}
}
// TODO: Because of a bug, those methods were not made visible which now cause issues with the fix as our interface are not consistent with the expectations
// are not consistent accross modules
/* & {
[TEntityName in keyof TEntitiesDtoConfig as `create${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(data: any[], sharedContext?: Context): Promise<
TEntitiesDtoConfig[TEntityName]["dto"][]
>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `create${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(data: any, sharedContext?: Context): Promise<
TEntitiesDtoConfig[TEntityName]["dto"][]
>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `update${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(
data: TEntitiesDtoConfig[TEntityName]["update"][],
sharedContext?: Context
): Promise<TEntitiesDtoConfig[TEntityName]["dto"][]>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `update${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(
data: TEntitiesDtoConfig[TEntityName]["update"],
sharedContext?: Context
): Promise<TEntitiesDtoConfig[TEntityName]["dto"]>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `update${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(
idOrdSelector: any,
data: TEntitiesDtoConfig[TEntityName]["update"],
sharedContext?: Context
): Promise<TEntitiesDtoConfig[TEntityName]["dto"][]>
}
}*/
/** /**
* @internal * @internal
*/ */
@@ -263,6 +66,36 @@ function buildMethodNamesFromModel(
}, {}) }, {})
} }
/**
* Accessible from the MedusaService, holds the model objects when provided
*/
export const MedusaServiceModelObjectsSymbol = Symbol.for(
"MedusaServiceModelObjectsSymbol"
)
/**
* Symbol to mark a class as a Medusa service
*/
export const MedusaServiceSymbol = Symbol.for("MedusaServiceSymbol")
/**
* Accessible from the MedusaService, holds the entity name to linkable keys map
* to be used for softDelete and restore methods
*/
export const MedusaServiceEntityNameToLinkableKeysMapSymbol = Symbol.for(
"MedusaServiceEntityNameToLinkableKeysMapSymbol"
)
/**
* Check if a value is a Medusa service
* @param value
*/
export function isMedusaService(
value: any
): value is MedusaServiceReturnType<any> {
return value && value?.prototype[MedusaServiceSymbol]
}
/** /**
* Factory function for creating an abstract module service * Factory function for creating an abstract module service
* *
@@ -281,26 +114,22 @@ function buildMethodNamesFromModel(
* RuleType, * RuleType,
* } * }
* *
* class MyService extends ModulesSdkUtils.MedusaService(entities, entityNameToLinkableKeysMap) {} * class MyService extends ModulesSdkUtils.MedusaService(entities) {}
* *
* @param entities * @param entities
* @param entityNameToLinkableKeysMap
*/ */
export function MedusaService< export function MedusaService<
EntitiesConfig extends EntitiesConfigTemplate = { __empty: any }, const EntitiesConfig extends EntitiesConfigTemplate = { __empty: any },
TEntities extends TEntityEntries< const TEntities extends TEntityEntries<
ExtractKeysFromConfig<EntitiesConfig> ExtractKeysFromConfig<EntitiesConfig>
> = TEntityEntries<ExtractKeysFromConfig<EntitiesConfig>> > = TEntityEntries<ExtractKeysFromConfig<EntitiesConfig>>
>( >(
entities: TEntities, entities: TEntities
entityNameToLinkableKeysMap: MapToConfig = {} ): MedusaServiceReturnType<
): {
new (...args: any[]): AbstractModuleService<
EntitiesConfig extends { __empty: any } EntitiesConfig extends { __empty: any }
? ModelConfigurationsToConfigTemplate<TEntities> ? ModelConfigurationsToConfigTemplate<TEntities>
: EntitiesConfig : EntitiesConfig
> > {
} {
const buildAndAssignMethodImpl = function ( const buildAndAssignMethodImpl = function (
klassPrototype: any, klassPrototype: any,
method: string, method: string,
@@ -474,7 +303,7 @@ export function MedusaService<
// eg: product.id = product_id, variant.id = variant_id // eg: product.id = product_id, variant.id = variant_id
const mappedCascadedEntitiesMap = mapObjectTo( const mappedCascadedEntitiesMap = mapObjectTo(
cascadedEntitiesMap, cascadedEntitiesMap,
entityNameToLinkableKeysMap, this[MedusaServiceEntityNameToLinkableKeysMapSymbol],
{ {
pick: config.returnLinkableKeys, pick: config.returnLinkableKeys,
} }
@@ -506,7 +335,7 @@ export function MedusaService<
// eg: product.id = product_id, variant.id = variant_id // eg: product.id = product_id, variant.id = variant_id
mappedCascadedEntitiesMap = mapObjectTo( mappedCascadedEntitiesMap = mapObjectTo(
cascadedEntitiesMap, cascadedEntitiesMap,
entityNameToLinkableKeysMap, this[MedusaServiceEntityNameToLinkableKeysMapSymbol],
{ {
pick: config.returnLinkableKeys, pick: config.returnLinkableKeys,
} }
@@ -522,11 +351,23 @@ export function MedusaService<
} }
class AbstractModuleService_ { class AbstractModuleService_ {
[MedusaServiceSymbol] = true
static [MedusaServiceModelObjectsSymbol] = Object.values(
entities
) as unknown as MedusaServiceReturnType<
EntitiesConfig extends { __empty: any }
? ModelConfigurationsToConfigTemplate<TEntities>
: EntitiesConfig
>["$modelObjects"];
[MedusaServiceEntityNameToLinkableKeysMapSymbol]: MapToConfig
readonly __container__: Record<any, any> readonly __container__: Record<any, any>
readonly baseRepository_: RepositoryService readonly baseRepository_: RepositoryService
readonly eventBusModuleService_: IEventBusModuleService; readonly eventBusModuleService_: IEventBusModuleService
[key: string]: any __joinerConfig?(): ModuleJoinerConfig
constructor(container: Record<any, any>) { constructor(container: Record<any, any>) {
this.__container__ = container this.__container__ = container
@@ -539,6 +380,11 @@ export function MedusaService<
this.eventBusModuleService_ = hasEventBusModuleService this.eventBusModuleService_ = hasEventBusModuleService
? this.__container__.eventBusModuleService ? this.__container__.eventBusModuleService
: undefined : undefined
this[MedusaServiceEntityNameToLinkableKeysMapSymbol] =
buildEntitiesNameToLinkableKeysMap(
this.__joinerConfig?.()?.linkableKeys ?? {}
)
} }
protected async emitEvents_(groupedEvents) { protected async emitEvents_(groupedEvents) {
@@ -563,7 +409,7 @@ export function MedusaService<
string, string,
TEntities[keyof TEntities], TEntities[keyof TEntities],
Record<string, string> Record<string, string>
][] = Object.entries(entities).map(([name, config]) => [ ][] = Object.entries(entities as {}).map(([name, config]) => [
name, name,
config as TEntities[keyof TEntities], config as TEntities[keyof TEntities],
buildMethodNamesFromModel(name, config as TEntities[keyof TEntities]), buildMethodNamesFromModel(name, config as TEntities[keyof TEntities]),
@@ -14,7 +14,7 @@ type Options = Partial<MikroORMOptions> & {
| EntityClass<AnyEntity> | EntityClass<AnyEntity>
| EntityClassGroup<AnyEntity> | EntityClassGroup<AnyEntity>
| EntitySchema | EntitySchema
| DmlEntity<any> | DmlEntity<any, any>
)[] )[]
databaseName: string databaseName: string
} }
@@ -0,0 +1,45 @@
import { Constructor, ModuleExports } from "@medusajs/types"
import { MedusaServiceModelObjectsSymbol } from "./medusa-service"
import {
buildLinkConfigFromDmlObjects,
defineJoinerConfig,
} from "./joiner-config-builder"
import { InfersLinksConfig } from "./types/links-config"
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 service
* @param loaders
* @constructor
*/
export function Module<
const Service extends Constructor<any>,
const ModelObjects extends DmlEntity<any, any>[] = Service extends {
$modelObjects: infer $DmlObjects
}
? $DmlObjects
: [],
Links = keyof ModelObjects extends never
? Record<string, any>
: InfersLinksConfig<ModelObjects>
>({
name = "",
service,
loaders,
}: ModuleExports<Service> & { name?: string }): ModuleExports<Service> & {
links: Links
} {
service.prototype.__joinerConfig ??= defineJoinerConfig(name)
const dmlObjects = service[MedusaServiceModelObjectsSymbol]
return {
service,
loaders,
links: (dmlObjects?.length
? buildLinkConfigFromDmlObjects(dmlObjects)
: {}) as Links,
}
}
@@ -0,0 +1,131 @@
import {
DMLSchema,
IDmlEntityConfig,
InferDmlEntityNameFromConfig,
SnakeCase,
} from "@medusajs/types"
import { DmlEntity } from "../../dml"
import { PrimaryKeyModifier } from "../../dml/properties/primary-key"
type FlattenUnion<T> = T extends { [K in keyof T]: infer U }
? { [K in keyof T]: U }
: never
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never
type InferLinkableKeyName<
Key,
Property,
DmlConfig extends IDmlEntityConfig
> = Property extends PrimaryKeyModifier<any, any>
? `${Lowercase<SnakeCase<InferDmlEntityNameFromConfig<DmlConfig>>>}_${Key &
string}`
: never
type InferSchemaLinkableKeys<T> = T extends DmlEntity<
infer Schema,
infer Config
>
? {
[K in keyof Schema as Schema[K] extends PrimaryKeyModifier<any, any>
? InferLinkableKeyName<K, Schema[K], Config>
: never]: InferDmlEntityNameFromConfig<Config>
}
: {}
type InferSchemasLinkableKeys<T extends DmlEntity<any, any>[]> = {
[K in keyof T]: InferSchemaLinkableKeys<T[K]>
}
type AggregateSchemasLinkableKeys<T extends DmlEntity<any, any>[]> = {
[K in keyof InferSchemasLinkableKeys<T>]: InferSchemasLinkableKeys<T>[K]
}
/**
* From an array of DmlEntity, returns a formatted object with the linkable keys
*
* @example:
*
* const user = model.define("user", {
* id: model.id(),
* name: model.text(),
* })
*
* const car = model.define("car", {
* id: model.id(),
* number_plate: model.text().primaryKey(),
* test: model.text(),
* })
*
* const linkableKeys = buildLinkableKeysFromDmlObjects([user, car]) // { user_id: 'user', car_number_plate: 'car' }
*
*/
export type InferLinkableKeys<T extends DmlEntity<any, any>[]> =
UnionToIntersection<FlattenUnion<AggregateSchemasLinkableKeys<T>>[0]>
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>
? {
[K in keyof Schema as Schema[K] extends PrimaryKeyModifier<any, any>
? InferPrimaryKeyNameOrNever<Schema, K>
: never]: {
linkable: InferLinkableKeyName<K, Schema[K], Config>
primaryKey: K
}
}
: {}
/**
* From an array of DmlEntity, returns a formatted object with the linkable keys
*
* @example:
*
* const user = model.define("user", {
* id: model.id(),
* name: model.text(),
* })
*
* const car = model.define("car", {
* id: model.id(),
* number_plate: model.text().primaryKey(),
* test: model.text(),
* })
*
* const linkConfig = buildLinkConfigFromDmlObjects([user, car])
* // {
* // user: {
* // id: {
* // linkable: 'user_id',
* // primaryKey: 'id'
* // },
* // toJSON() { ... }
* // },
* // car: {
* // number_plate: {
* // linkable: 'car_number_plate',
* // primaryKey: 'number_plate'
* // },
* // toJSON() { ... }
* // }
* // }
*
*/
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
}
}
}>
@@ -0,0 +1,261 @@
import {
Constructor,
Context,
FindConfig,
Pluralize,
RestoreReturn,
SoftDeleteReturn,
} from "@medusajs/types"
import { DmlEntity } from "../../dml"
export type BaseMethods =
| "retrieve"
| "list"
| "listAndCount"
| "delete"
| "softDelete"
| "restore"
| "create"
| "update"
export type ModelDTOConfig = {
dto: object
model?: DmlEntity<any, any>
create?: any
update?: any
/**
* @internal
* @deprecated
*/
singular?: string
/**
* @internal
* @deprecated
*/
plural?: string
}
export type EntitiesConfigTemplate = { [key: string]: ModelDTOConfig }
export type ModelConfigurationsToConfigTemplate<T extends TEntityEntries> = {
[Key in keyof T]: {
dto: T[Key] extends Constructor<any> ? InstanceType<T[Key]> : any
model: T[Key] extends { model: infer MODEL }
? MODEL
: T[Key] extends DmlEntity<any, any>
? T[Key]
: never
/**
* @deprecated
*/
create: any
update: any
/**
* @deprecated
*/
singular: T[Key] extends { singular: string } ? T[Key]["singular"] : Key
/**
* @deprecated
*/
plural: T[Key] extends { plural: string }
? T[Key]["plural"]
: Pluralize<Key & string>
}
}
/**
* @deprecated should all notion of singular and plural be removed once all modules are aligned with the convention
*/
export type ExtractSingularName<
T extends Record<any, any>,
K = keyof T
> = Capitalize<
T[K] extends { singular?: string } ? T[K]["singular"] & string : K & string
>
/**
* @deprecated should all notion of singular and plural be removed once all modules are aligned with the convention
* The pluralize will move to where it should be used instead
*/
export type ExtractPluralName<
T extends Record<any, any>,
K = keyof T
> = Capitalize<
T[K] extends {
plural?: string
}
? T[K]["plural"] & string
: Pluralize<K & string>
>
// TODO: The future expected entry will be a MODEL object but in the meantime we have to maintain backward compatibility for ouw own modules and therefore we need to support Constructor<any> as well as this temporary object
export type TEntityEntries<Keys = string> = Record<
Keys & string,
| DmlEntity<any, any>
/**
* @deprecated
*/
| Constructor<any>
/**
* @deprecated
*/
| { name?: string; singular?: string; plural?: string }
>
export type ExtractKeysFromConfig<EntitiesConfig> = EntitiesConfig extends {
__empty: any
}
? string
: keyof EntitiesConfig
export type AbstractModuleService<
TEntitiesDtoConfig extends Record<string, any>
> = {
[TEntityName in keyof TEntitiesDtoConfig as `retrieve${ExtractSingularName<
TEntitiesDtoConfig,
TEntityName
>}`]: (
id: string,
config?: FindConfig<any>,
sharedContext?: Context
) => Promise<TEntitiesDtoConfig[TEntityName]["dto"]>
} & {
[TEntityName in keyof TEntitiesDtoConfig as `list${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: (
filters?: any,
config?: FindConfig<any>,
sharedContext?: Context
) => Promise<TEntitiesDtoConfig[TEntityName]["dto"][]>
} & {
[TEntityName in keyof TEntitiesDtoConfig as `listAndCount${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(filters?: any, config?: FindConfig<any>, sharedContext?: Context): Promise<
[TEntitiesDtoConfig[TEntityName]["dto"][], number]
>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `delete${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(
primaryKeyValues: string | object | string[] | object[],
sharedContext?: Context
): Promise<void>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `softDelete${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
<TReturnableLinkableKeys extends string>(
primaryKeyValues: string | object | string[] | object[],
config?: SoftDeleteReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `restore${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
<TReturnableLinkableKeys extends string>(
primaryKeyValues: string | object | string[] | object[],
config?: RestoreReturn<TReturnableLinkableKeys>,
sharedContext?: Context
): Promise<Record<string, string[]> | void>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `create${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(...args: any[]): Promise<any>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `update${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(...args: any[]): Promise<any>
}
}
// TODO: Because of a bug, those methods were not made visible which now cause issues with the fix as our interface are not consistent with the expectations
// are not consistent accross modules
/* & {
[TEntityName in keyof TEntitiesDtoConfig as `create${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(data: any[], sharedContext?: Context): Promise<
TEntitiesDtoConfig[TEntityName]["dto"][]
>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `create${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(data: any, sharedContext?: Context): Promise<
TEntitiesDtoConfig[TEntityName]["dto"][]
>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `update${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(
data: TEntitiesDtoConfig[TEntityName]["update"][],
sharedContext?: Context
): Promise<TEntitiesDtoConfig[TEntityName]["dto"][]>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `update${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(
data: TEntitiesDtoConfig[TEntityName]["update"],
sharedContext?: Context
): Promise<TEntitiesDtoConfig[TEntityName]["dto"]>
}
} & {
[TEntityName in keyof TEntitiesDtoConfig as `update${ExtractPluralName<
TEntitiesDtoConfig,
TEntityName
>}`]: {
(
idOrdSelector: any,
data: TEntitiesDtoConfig[TEntityName]["update"],
sharedContext?: Context
): Promise<TEntitiesDtoConfig[TEntityName]["dto"][]>
}
}*/
type InferModelFromConfig<T> = {
[K in keyof T as T[K] extends { model: any }
? K
: K extends DmlEntity<any, any>
? K
: never]: T[K] extends {
model: infer MODEL
}
? MODEL extends DmlEntity<any, any>
? MODEL
: never
: T[K] extends DmlEntity<any, any>
? T[K]
: never
}
export type MedusaServiceReturnType<ModelsConfig extends Record<any, any>> = {
new (...args: any[]): AbstractModuleService<ModelsConfig>
$modelObjects: InferModelFromConfig<ModelsConfig>[keyof InferModelFromConfig<ModelsConfig>][]
}
@@ -1,11 +1,3 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.API_KEY) export const joinerConfig = defineJoinerConfig(Modules.API_KEY)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -11,7 +11,7 @@ import {
ModuleJoinerConfig, ModuleJoinerConfig,
ModulesSdkTypes, ModulesSdkTypes,
} from "@medusajs/types" } from "@medusajs/types"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import { ApiKey } from "@models" import { ApiKey } from "@models"
import { import {
CreateApiKeyDTO, CreateApiKeyDTO,
@@ -41,7 +41,7 @@ type InjectedDependencies = {
export default class ApiKeyModuleService export default class ApiKeyModuleService
extends MedusaService<{ extends MedusaService<{
ApiKey: { dto: ApiKeyTypes.ApiKeyDTO } ApiKey: { dto: ApiKeyTypes.ApiKeyDTO }
}>({ ApiKey }, entityNameToLinkableKeysMap) }>({ ApiKey })
implements IApiKeyModuleService implements IApiKeyModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
+2 -10
View File
@@ -1,14 +1,6 @@
import { AuthIdentity } from "@models" import { AuthIdentity } from "@models"
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.AUTH, { export const joinerConfig = defineJoinerConfig(Modules.AUTH, {
entityQueryingConfig: [AuthIdentity], models: [AuthIdentity],
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -12,7 +12,7 @@ import {
import { AuthIdentity, ProviderIdentity } from "@models" import { AuthIdentity, ProviderIdentity } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import { import {
InjectManager, InjectManager,
@@ -32,7 +32,7 @@ export default class AuthModuleService
extends MedusaService<{ extends MedusaService<{
AuthIdentity: { dto: AuthTypes.AuthIdentityDTO } AuthIdentity: { dto: AuthTypes.AuthIdentityDTO }
ProviderIdentity: { dto: AuthTypes.ProviderIdentityDTO } ProviderIdentity: { dto: AuthTypes.ProviderIdentityDTO }
}>({ AuthIdentity, ProviderIdentity }, entityNameToLinkableKeysMap) }>({ AuthIdentity, ProviderIdentity })
implements AuthTypes.IAuthModuleService implements AuthTypes.IAuthModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
+1 -9
View File
@@ -1,11 +1,3 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.CART) export const joinerConfig = defineJoinerConfig(Modules.CART)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -39,7 +39,7 @@ import {
UpdateLineItemDTO, UpdateLineItemDTO,
UpdateShippingMethodTaxLineDTO, UpdateShippingMethodTaxLineDTO,
} from "@types" } from "@types"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
@@ -74,7 +74,7 @@ export default class CartModuleService
ShippingMethod: { dto: CartTypes.CartShippingMethodDTO } ShippingMethod: { dto: CartTypes.CartShippingMethodDTO }
ShippingMethodAdjustment: { dto: CartTypes.ShippingMethodAdjustmentDTO } ShippingMethodAdjustment: { dto: CartTypes.ShippingMethodAdjustmentDTO }
ShippingMethodTaxLine: { dto: CartTypes.ShippingMethodTaxLineDTO } ShippingMethodTaxLine: { dto: CartTypes.ShippingMethodTaxLineDTO }
}>(generateMethodForModels, entityNameToLinkableKeysMap) }>(generateMethodForModels)
implements ICartModuleService implements ICartModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
+4 -5
View File
@@ -1,13 +1,12 @@
import { CurrencyModuleService } from "@services" import { CurrencyModuleService } from "@services"
import initialDataLoader from "./loaders/initial-data" import initialDataLoader from "./loaders/initial-data"
import { ModuleExports } from "@medusajs/types" import { Module, Modules } from "@medusajs/utils"
const service = CurrencyModuleService const service = CurrencyModuleService
const loaders = [initialDataLoader] const loaders = [initialDataLoader]
export const moduleDefinition: ModuleExports = { export default Module({
name: Modules.CURRENCY,
service, service,
loaders, loaders,
} })
export default moduleDefinition
@@ -1,9 +1,4 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.CURRENCY, { export const joinerConfig = defineJoinerConfig(Modules.CURRENCY, {
primaryKeys: ["code"], primaryKeys: ["code"],
@@ -11,6 +6,3 @@ export const joinerConfig = defineJoinerConfig(Modules.CURRENCY, {
currency_code: "currency", currency_code: "currency",
}, },
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -1,7 +1,7 @@
import { model } from "@medusajs/utils" import { model } from "@medusajs/utils"
export default model.define("currency", { export default model.define("currency", {
code: model.text().primaryKey().searchable(), code: model.text().searchable().primaryKey(),
symbol: model.text(), symbol: model.text(),
symbol_native: model.text(), symbol_native: model.text(),
name: model.text().searchable(), name: model.text().searchable(),
@@ -13,7 +13,7 @@ import {
import { MedusaService } from "@medusajs/utils" import { MedusaService } from "@medusajs/utils"
import { Currency } from "@models" import { Currency } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
@@ -22,8 +22,8 @@ type InjectedDependencies = {
export default class CurrencyModuleService export default class CurrencyModuleService
extends MedusaService<{ extends MedusaService<{
Currency: { dto: CurrencyTypes.CurrencyDTO } Currency: { dto: CurrencyTypes.CurrencyDTO; model: typeof Currency }
}>({ Currency }, entityNameToLinkableKeysMap) }>({ Currency })
implements ICurrencyModuleService implements ICurrencyModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
@@ -1,9 +1,4 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.CUSTOMER, { export const joinerConfig = defineJoinerConfig(Modules.CUSTOMER, {
alias: [ alias: [
@@ -16,6 +11,3 @@ export const joinerConfig = defineJoinerConfig(Modules.CUSTOMER, {
}, },
], ],
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -26,7 +26,7 @@ import {
CustomerGroup, CustomerGroup,
CustomerGroupCustomer, CustomerGroupCustomer,
} from "@models" } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
@@ -42,10 +42,7 @@ export default class CustomerModuleService
Customer: { dto: CustomerDTO } Customer: { dto: CustomerDTO }
CustomerGroup: { dto: CustomerGroupDTO } CustomerGroup: { dto: CustomerGroupDTO }
CustomerGroupCustomer: { dto: CustomerGroupCustomerDTO } CustomerGroupCustomer: { dto: CustomerGroupCustomerDTO }
}>( }>({ Address, Customer, CustomerGroup, CustomerGroupCustomer })
{ Address, Customer, CustomerGroup, CustomerGroupCustomer },
entityNameToLinkableKeysMap
)
implements ICustomerModuleService implements ICustomerModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
+2 -10
View File
@@ -1,13 +1,5 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.FILE, { export const joinerConfig = defineJoinerConfig(Modules.FILE, {
entityQueryingConfig: [{ name: "File" }], models: [{ name: "File" }],
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap({})
@@ -1,9 +1,4 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
import { import {
Fulfillment, Fulfillment,
FulfillmentSet, FulfillmentSet,
@@ -19,6 +14,3 @@ export const joinerConfig = defineJoinerConfig(Modules.FULFILLMENT, {
shipping_option_rule_id: ShippingOptionRule.name, shipping_option_rule_id: ShippingOptionRule.name,
}, },
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -47,7 +47,7 @@ import {
isContextValid, isContextValid,
validateAndNormalizeRules, validateAndNormalizeRules,
} from "@utils" } from "@utils"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import { UpdateShippingOptionsInput } from "../types/service" import { UpdateShippingOptionsInput } from "../types/service"
import { buildCreatedShippingOptionEvents } from "../utils/events" import { buildCreatedShippingOptionEvents } from "../utils/events"
import FulfillmentProviderService from "./fulfillment-provider" import FulfillmentProviderService from "./fulfillment-provider"
@@ -87,7 +87,7 @@ export default class FulfillmentModuleService
ShippingOptionRule: { dto: FulfillmentTypes.ShippingOptionRuleDTO } ShippingOptionRule: { dto: FulfillmentTypes.ShippingOptionRuleDTO }
ShippingOptionType: { dto: FulfillmentTypes.ShippingOptionTypeDTO } ShippingOptionType: { dto: FulfillmentTypes.ShippingOptionTypeDTO }
FulfillmentProvider: { dto: FulfillmentTypes.FulfillmentProviderDTO } FulfillmentProvider: { dto: FulfillmentTypes.FulfillmentProviderDTO }
}>(generateMethodForModels, entityNameToLinkableKeysMap) }>(generateMethodForModels)
implements IFulfillmentModuleService implements IFulfillmentModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
@@ -1,9 +1,4 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.INVENTORY, { export const joinerConfig = defineJoinerConfig(Modules.INVENTORY, {
alias: [ alias: [
@@ -35,6 +30,3 @@ export const joinerConfig = defineJoinerConfig(Modules.INVENTORY, {
}, },
], ],
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -8,9 +8,10 @@ type InjectedDependencies = {
inventoryLevelRepository: InventoryLevelRepository inventoryLevelRepository: InventoryLevelRepository
} }
export default class InventoryLevelService extends ModulesSdkUtils.MedusaInternalService<InjectedDependencies>( export default class InventoryLevelService extends ModulesSdkUtils.MedusaInternalService<
InjectedDependencies,
InventoryLevel InventoryLevel
)<InventoryLevel> { >(InventoryLevel) {
protected readonly inventoryLevelRepository: InventoryLevelRepository protected readonly inventoryLevelRepository: InventoryLevelRepository
constructor(container: InjectedDependencies) { constructor(container: InjectedDependencies) {
@@ -11,22 +11,22 @@ import {
} from "@medusajs/types" } from "@medusajs/types"
import { IInventoryService } from "@medusajs/types/dist/inventory" import { IInventoryService } from "@medusajs/types/dist/inventory"
import { import {
arrayDifference,
CommonEvents, CommonEvents,
EmitEvents, EmitEvents,
InjectManager, InjectManager,
InjectTransactionManager, InjectTransactionManager,
InventoryEvents, InventoryEvents,
isDefined,
isString,
MedusaContext, MedusaContext,
MedusaError, MedusaError,
MedusaService, MedusaService,
arrayDifference,
isDefined,
isString,
partitionArray, partitionArray,
promiseAll, promiseAll,
} from "@medusajs/utils" } from "@medusajs/utils"
import { InventoryItem, InventoryLevel, ReservationItem } from "@models" import { InventoryItem, InventoryLevel, ReservationItem } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import InventoryLevelService from "./inventory-level" import InventoryLevelService from "./inventory-level"
type InjectedDependencies = { type InjectedDependencies = {
@@ -47,14 +47,11 @@ export default class InventoryModuleService
ReservationItem: { ReservationItem: {
dto: InventoryTypes.ReservationItemDTO dto: InventoryTypes.ReservationItemDTO
} }
}>( }>({
{
InventoryItem, InventoryItem,
InventoryLevel, InventoryLevel,
ReservationItem, ReservationItem,
}, })
entityNameToLinkableKeysMap
)
implements IInventoryService implements IInventoryService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
@@ -1,13 +1,5 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.NOTIFICATION, { export const joinerConfig = defineJoinerConfig(Modules.NOTIFICATION, {
entityQueryingConfig: [{ name: "Notification" }], models: [{ name: "Notification" }],
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -1,12 +1,12 @@
import { import {
Context, Context,
DAL, DAL,
InferEntityType,
INotificationModuleService, INotificationModuleService,
InternalModuleDeclaration, InternalModuleDeclaration,
ModuleJoinerConfig, ModuleJoinerConfig,
ModulesSdkTypes, ModulesSdkTypes,
NotificationTypes, NotificationTypes,
InferEntityType,
} from "@medusajs/types" } from "@medusajs/types"
import { import {
InjectManager, InjectManager,
@@ -17,7 +17,7 @@ import {
promiseAll, promiseAll,
} from "@medusajs/utils" } from "@medusajs/utils"
import { Notification } from "@models" import { Notification } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import NotificationProviderService from "./notification-provider" import NotificationProviderService from "./notification-provider"
type InjectedDependencies = { type InjectedDependencies = {
@@ -31,7 +31,7 @@ type InjectedDependencies = {
export default class NotificationModuleService export default class NotificationModuleService
extends MedusaService<{ extends MedusaService<{
Notification: { dto: NotificationTypes.NotificationDTO } Notification: { dto: NotificationTypes.NotificationDTO }
}>({ Notification }, entityNameToLinkableKeysMap) }>({ Notification })
implements INotificationModuleService implements INotificationModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
@@ -12,9 +12,10 @@ type InjectedDependencies = {
]: NotificationTypes.INotificationProvider ]: NotificationTypes.INotificationProvider
} }
export default class NotificationProviderService extends ModulesSdkUtils.MedusaInternalService<InjectedDependencies>( export default class NotificationProviderService extends ModulesSdkUtils.MedusaInternalService<
NotificationProvider InjectedDependencies,
) { typeof NotificationProvider
>(NotificationProvider) {
protected readonly notificationProviderRepository_: DAL.RepositoryService< protected readonly notificationProviderRepository_: DAL.RepositoryService<
InferEntityType<typeof NotificationProvider> InferEntityType<typeof NotificationProvider>
> >
@@ -50,6 +51,8 @@ export default class NotificationProviderService extends ModulesSdkUtils.MedusaI
): Promise<InferEntityType<typeof NotificationProvider> | undefined> { ): Promise<InferEntityType<typeof NotificationProvider> | undefined> {
if (!this.providersCache) { if (!this.providersCache) {
const providers = await this.notificationProviderRepository_.find() const providers = await this.notificationProviderRepository_.find()
type name = (typeof NotificationProvider)["name"]
this.providersCache = new Map( this.providersCache = new Map(
providers.flatMap((provider) => providers.flatMap((provider) =>
provider.channels.map((c) => [c, provider]) provider.channels.map((c) => [c, provider])
+1 -9
View File
@@ -1,12 +1,4 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
// TODO: review configuration // TODO: review configuration
export const joinerConfig = defineJoinerConfig(Modules.ORDER) export const joinerConfig = defineJoinerConfig(Modules.ORDER)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -20,9 +20,10 @@ type InjectedDependencies = {
orderChangeRepository: DAL.RepositoryService orderChangeRepository: DAL.RepositoryService
} }
export default class OrderChangeService extends ModulesSdkUtils.MedusaInternalService<InjectedDependencies>( export default class OrderChangeService extends ModulesSdkUtils.MedusaInternalService<
InjectedDependencies,
OrderChange OrderChange
)<OrderChange> { >(OrderChange) {
protected readonly orderChangeRepository_: RepositoryService<OrderChange> protected readonly orderChangeRepository_: RepositoryService<OrderChange>
constructor(container: InjectedDependencies) { constructor(container: InjectedDependencies) {
@@ -65,7 +65,7 @@ import {
UpdateOrderLineItemTaxLineDTO, UpdateOrderLineItemTaxLineDTO,
UpdateOrderShippingMethodTaxLineDTO, UpdateOrderShippingMethodTaxLineDTO,
} from "@types" } from "@types"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import { import {
applyChangesToOrder, applyChangesToOrder,
ApplyOrderChangeDTO, ApplyOrderChangeDTO,
@@ -165,7 +165,7 @@ export default class OrderModuleService<
ReturnItem: { dto: any } // TODO: Add return item dto ReturnItem: { dto: any } // TODO: Add return item dto
OrderClaim: { dto: any } // TODO: Add claim dto OrderClaim: { dto: any } // TODO: Add claim dto
OrderExchange: { dto: any } // TODO: Add exchange dto OrderExchange: { dto: any } // TODO: Add exchange dto
}>(generateMethodForModels, entityNameToLinkableKeysMap) }>(generateMethodForModels)
implements IOrderModuleService implements IOrderModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
@@ -17,9 +17,10 @@ type InjectedDependencies = {
orderRepository: DAL.RepositoryService orderRepository: DAL.RepositoryService
} }
export default class OrderService extends ModulesSdkUtils.MedusaInternalService<InjectedDependencies>( export default class OrderService extends ModulesSdkUtils.MedusaInternalService<
InjectedDependencies,
Order Order
)<Order> { >(Order) {
protected readonly orderRepository_: RepositoryService<Order> protected readonly orderRepository_: RepositoryService<Order>
constructor(container: InjectedDependencies) { constructor(container: InjectedDependencies) {
+2 -15
View File
@@ -1,9 +1,4 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
import { import {
Payment, Payment,
PaymentCollection, PaymentCollection,
@@ -12,18 +7,10 @@ import {
} from "@models" } from "@models"
export const joinerConfig = defineJoinerConfig(Modules.PAYMENT, { export const joinerConfig = defineJoinerConfig(Modules.PAYMENT, {
entityQueryingConfig: [ models: [Payment, PaymentCollection, PaymentProvider, PaymentSession],
Payment,
PaymentCollection,
PaymentProvider,
PaymentSession,
],
linkableKeys: { linkableKeys: {
payment_id: Payment.name, payment_id: Payment.name,
payment_collection_id: PaymentCollection.name, payment_collection_id: PaymentCollection.name,
payment_provider_id: PaymentProvider.name, payment_provider_id: PaymentProvider.name,
}, },
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -48,7 +48,7 @@ import {
PaymentSession, PaymentSession,
Refund, Refund,
} from "@models" } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import PaymentProviderService from "./payment-provider" import PaymentProviderService from "./payment-provider"
type InjectedDependencies = { type InjectedDependencies = {
@@ -76,7 +76,7 @@ export default class PaymentModuleService
Payment: { dto: PaymentDTO } Payment: { dto: PaymentDTO }
Capture: { dto: CaptureDTO } Capture: { dto: CaptureDTO }
Refund: { dto: RefundDTO } Refund: { dto: RefundDTO }
}>(generateMethodForModels, entityNameToLinkableKeysMap) }>(generateMethodForModels)
implements IPaymentModuleService implements IPaymentModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
+2 -10
View File
@@ -1,19 +1,11 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
import { Price, PriceList, PriceSet } from "@models" import { Price, PriceList, PriceSet } from "@models"
export const joinerConfig = defineJoinerConfig(Modules.PRICING, { export const joinerConfig = defineJoinerConfig(Modules.PRICING, {
entityQueryingConfig: [PriceSet, PriceList, Price], models: [PriceSet, PriceList, Price],
linkableKeys: { linkableKeys: {
price_set_id: PriceSet.name, price_set_id: PriceSet.name,
price_list_id: PriceList.name, price_list_id: PriceList.name,
price_id: Price.name, price_id: Price.name,
}, },
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -38,7 +38,7 @@ import { Price, PriceList, PriceListRule, PriceRule, PriceSet } from "@models"
import { ServiceTypes } from "@types" import { ServiceTypes } from "@types"
import { eventBuilders, validatePriceListDates } from "@utils" import { eventBuilders, validatePriceListDates } from "@utils"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import { CreatePriceListDTO, UpsertPriceDTO } from "src/types/services" import { CreatePriceListDTO, UpsertPriceDTO } from "src/types/services"
type InjectedDependencies = { type InjectedDependencies = {
@@ -70,7 +70,7 @@ export default class PricingModuleService
} }
PriceList: { dto: PricingTypes.PriceListDTO } PriceList: { dto: PricingTypes.PriceListDTO }
PriceListRule: { dto: PricingTypes.PriceListRuleDTO } PriceListRule: { dto: PricingTypes.PriceListRuleDTO }
}>(generateMethodForModels, entityNameToLinkableKeysMap) }>(generateMethodForModels)
implements PricingTypes.IPricingModuleService implements PricingTypes.IPricingModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
@@ -1,11 +1,7 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.PRODUCT, { export const joinerConfig = defineJoinerConfig(Modules.PRODUCT, {
primaryKeys: ["id", "handle"],
// This module provides more alias than the default config builder // This module provides more alias than the default config builder
alias: [ alias: [
{ {
@@ -58,6 +54,3 @@ export const joinerConfig = defineJoinerConfig(Modules.PRODUCT, {
}, },
], ],
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -51,7 +51,7 @@ import {
UpdateTypeInput, UpdateTypeInput,
} from "../types" } from "../types"
import { eventBuilders } from "../utils" import { eventBuilders } from "../utils"
import { entityNameToLinkableKeysMap, joinerConfig } from "./../joiner-config" import { joinerConfig } from "./../joiner-config"
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
@@ -90,8 +90,7 @@ export default class ProductModuleService
ProductVariant: { ProductVariant: {
dto: ProductTypes.ProductVariantDTO dto: ProductTypes.ProductVariantDTO
} }
}>( }>({
{
Product, Product,
ProductCategory, ProductCategory,
ProductCollection, ProductCollection,
@@ -99,9 +98,7 @@ export default class ProductModuleService
ProductTag, ProductTag,
ProductType, ProductType,
ProductVariant, ProductVariant,
}, })
entityNameToLinkableKeysMap
)
implements ProductTypes.IProductModuleService implements ProductTypes.IProductModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
@@ -18,9 +18,10 @@ type NormalizedFilterableProductProps = ProductTypes.FilterableProductProps & {
} }
} }
export default class ProductService extends ModulesSdkUtils.MedusaInternalService<InjectedDependencies>( export default class ProductService extends ModulesSdkUtils.MedusaInternalService<
InjectedDependencies,
Product Product
)<Product> { >(Product) {
protected readonly productRepository_: DAL.RepositoryService<Product> protected readonly productRepository_: DAL.RepositoryService<Product>
constructor({ productRepository }: InjectedDependencies) { constructor({ productRepository }: InjectedDependencies) {
@@ -1,19 +1,11 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
import { Campaign, Promotion, PromotionRule } from "@models" import { Campaign, Promotion, PromotionRule } from "@models"
export const joinerConfig = defineJoinerConfig(Modules.PROMOTION, { export const joinerConfig = defineJoinerConfig(Modules.PROMOTION, {
entityQueryingConfig: [Promotion, Campaign, PromotionRule], models: [Promotion, Campaign, PromotionRule],
linkableKeys: { linkableKeys: {
promotion_id: Promotion.name, promotion_id: Promotion.name,
campaign_id: Campaign.name, campaign_id: Campaign.name,
promotion_rule_id: PromotionRule.name, promotion_rule_id: PromotionRule.name,
}, },
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -23,7 +23,6 @@ import {
MedusaContext, MedusaContext,
MedusaError, MedusaError,
MedusaService, MedusaService,
ModulesSdkUtils,
PromotionType, PromotionType,
transformPropertiesToBigNumber, transformPropertiesToBigNumber,
} from "@medusajs/utils" } from "@medusajs/utils"
@@ -54,7 +53,7 @@ import {
validateApplicationMethodAttributes, validateApplicationMethodAttributes,
validatePromotionRuleAttributes, validatePromotionRuleAttributes,
} from "@utils" } from "@utils"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import { CreatePromotionRuleValueDTO } from "../types/promotion-rule-value" import { CreatePromotionRuleValueDTO } from "../types/promotion-rule-value"
type InjectedDependencies = { type InjectedDependencies = {
@@ -75,17 +74,14 @@ export default class PromotionModuleService
CampaignBudget: { dto: PromotionTypes.CampaignBudgetDTO } CampaignBudget: { dto: PromotionTypes.CampaignBudgetDTO }
PromotionRule: { dto: PromotionTypes.PromotionRuleDTO } PromotionRule: { dto: PromotionTypes.PromotionRuleDTO }
PromotionRuleValue: { dto: PromotionTypes.PromotionRuleValueDTO } PromotionRuleValue: { dto: PromotionTypes.PromotionRuleValueDTO }
}>( }>({
{
Promotion, Promotion,
ApplicationMethod, ApplicationMethod,
Campaign, Campaign,
CampaignBudget, CampaignBudget,
PromotionRule, PromotionRule,
PromotionRuleValue, PromotionRuleValue,
}, })
entityNameToLinkableKeysMap
)
implements PromotionTypes.IPromotionModuleService implements PromotionTypes.IPromotionModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
+1 -9
View File
@@ -1,11 +1,3 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.REGION) export const joinerConfig = defineJoinerConfig(Modules.REGION)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -3,9 +3,9 @@ import {
CreateRegionDTO, CreateRegionDTO,
DAL, DAL,
FilterableRegionProps, FilterableRegionProps,
IRegionModuleService,
InferEntityType, InferEntityType,
InternalModuleDeclaration, InternalModuleDeclaration,
IRegionModuleService,
ModuleJoinerConfig, ModuleJoinerConfig,
ModulesSdkTypes, ModulesSdkTypes,
RegionCountryDTO, RegionCountryDTO,
@@ -15,20 +15,20 @@ import {
UpsertRegionDTO, UpsertRegionDTO,
} from "@medusajs/types" } from "@medusajs/types"
import { import {
arrayDifference,
getDuplicates,
InjectManager, InjectManager,
InjectTransactionManager, InjectTransactionManager,
isString,
MedusaContext, MedusaContext,
MedusaError, MedusaError,
MedusaService, MedusaService,
arrayDifference,
getDuplicates,
isString,
promiseAll, promiseAll,
removeUndefined, removeUndefined,
} from "@medusajs/utils" } from "@medusajs/utils"
import { RegionCountry as Country, Region } from "@models" import { Region, RegionCountry as Country } from "@models"
import { UpdateRegionInput } from "@types" import { UpdateRegionInput } from "@types"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
@@ -44,7 +44,7 @@ export default class RegionModuleService
Country: { Country: {
dto: RegionCountryDTO dto: RegionCountryDTO
} }
}>({ Region, Country }, entityNameToLinkableKeysMap) }>({ Region, Country })
implements IRegionModuleService implements IRegionModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
@@ -1,11 +1,3 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.SALES_CHANNEL) export const joinerConfig = defineJoinerConfig(Modules.SALES_CHANNEL)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -9,6 +9,7 @@ import {
ModulesSdkTypes, ModulesSdkTypes,
SalesChannelDTO, SalesChannelDTO,
UpdateSalesChannelDTO, UpdateSalesChannelDTO,
UpsertSalesChannelDTO,
} from "@medusajs/types" } from "@medusajs/types"
import { import {
InjectManager, InjectManager,
@@ -20,10 +21,8 @@ import {
} from "@medusajs/utils" } from "@medusajs/utils"
import { SalesChannel } from "@models" import { SalesChannel } from "@models"
import { UpsertSalesChannelDTO } from "@medusajs/types"
import { UpdateSalesChanneInput } from "@types" import { UpdateSalesChanneInput } from "@types"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
@@ -31,10 +30,9 @@ type InjectedDependencies = {
} }
export default class SalesChannelModuleService export default class SalesChannelModuleService
extends MedusaService<{ SalesChannel: { dto: SalesChannelDTO } }>( extends MedusaService<{ SalesChannel: { dto: SalesChannelDTO } }>({
{ SalesChannel }, SalesChannel,
entityNameToLinkableKeysMap })
)
implements ISalesChannelModuleService implements ISalesChannelModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
@@ -1,9 +1,4 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
import { StockLocation } from "./models" import { StockLocation } from "./models"
export const joinerConfig = defineJoinerConfig(Modules.STOCK_LOCATION, { export const joinerConfig = defineJoinerConfig(Modules.STOCK_LOCATION, {
@@ -12,6 +7,3 @@ export const joinerConfig = defineJoinerConfig(Modules.STOCK_LOCATION, {
location_id: StockLocation.name, location_id: StockLocation.name,
}, },
}) })
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -21,7 +21,7 @@ import {
MedusaService, MedusaService,
promiseAll, promiseAll,
} from "@medusajs/utils" } from "@medusajs/utils"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import { StockLocation, StockLocationAddress } from "../models" import { StockLocation, StockLocationAddress } from "../models"
type InjectedDependencies = { type InjectedDependencies = {
@@ -38,7 +38,7 @@ export default class StockLocationModuleService
extends MedusaService<{ extends MedusaService<{
StockLocation: { dto: StockLocationTypes.StockLocationDTO } StockLocation: { dto: StockLocationTypes.StockLocationDTO }
StockLocationAddress: { dto: StockLocationTypes.StockLocationAddressDTO } StockLocationAddress: { dto: StockLocationTypes.StockLocationAddressDTO }
}>({ StockLocation, StockLocationAddress }, entityNameToLinkableKeysMap) }>({ StockLocation, StockLocationAddress })
implements IStockLocationService implements IStockLocationService
{ {
protected readonly eventBusModuleService_: IEventBusService protected readonly eventBusModuleService_: IEventBusService
+1 -9
View File
@@ -1,11 +1,3 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.STORE) export const joinerConfig = defineJoinerConfig(Modules.STORE)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -20,7 +20,7 @@ import {
} from "@medusajs/utils" } from "@medusajs/utils"
import { Store, StoreCurrency } from "@models" import { Store, StoreCurrency } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import { UpdateStoreInput } from "@types" import { UpdateStoreInput } from "@types"
type InjectedDependencies = { type InjectedDependencies = {
@@ -32,7 +32,7 @@ export default class StoreModuleService
extends MedusaService<{ extends MedusaService<{
Store: { dto: StoreTypes.StoreDTO } Store: { dto: StoreTypes.StoreDTO }
StoreCurrency: { dto: StoreTypes.StoreCurrencyDTO } StoreCurrency: { dto: StoreTypes.StoreCurrencyDTO }
}>({ Store, StoreCurrency }, entityNameToLinkableKeysMap) }>({ Store, StoreCurrency })
implements IStoreModuleService implements IStoreModuleService
{ {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
+1 -9
View File
@@ -1,11 +1,3 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.TAX) export const joinerConfig = defineJoinerConfig(Modules.TAX)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -20,7 +20,7 @@ import {
promiseAll, promiseAll,
} from "@medusajs/utils" } from "@medusajs/utils"
import { TaxProvider, TaxRate, TaxRateRule, TaxRegion } from "@models" import { TaxProvider, TaxRate, TaxRateRule, TaxRegion } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
@@ -44,7 +44,7 @@ export default class TaxModuleService
TaxRegion: { dto: TaxTypes.TaxRegionDTO } TaxRegion: { dto: TaxTypes.TaxRegionDTO }
TaxRateRule: { dto: TaxTypes.TaxRateRuleDTO } TaxRateRule: { dto: TaxTypes.TaxRateRuleDTO }
TaxProvider: { dto: TaxTypes.TaxProviderDTO } TaxProvider: { dto: TaxTypes.TaxProviderDTO }
}>(generateForModels, entityNameToLinkableKeysMap) }>(generateForModels)
implements ITaxModuleService implements ITaxModuleService
{ {
protected readonly container_: InjectedDependencies protected readonly container_: InjectedDependencies
+1 -9
View File
@@ -1,11 +1,3 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.USER) export const joinerConfig = defineJoinerConfig(Modules.USER)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -19,7 +19,7 @@ import {
UserEvents, UserEvents,
} from "@medusajs/utils" } from "@medusajs/utils"
import jwt, { JwtPayload } from "jsonwebtoken" import jwt, { JwtPayload } from "jsonwebtoken"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
import crypto from "node:crypto" import crypto from "node:crypto"
import { Invite, User } from "@models" import { Invite, User } from "@models"
@@ -41,7 +41,7 @@ export default class UserModuleService
Invite: { Invite: {
dto: UserTypes.InviteDTO dto: UserTypes.InviteDTO
} }
}>({ User, Invite }, entityNameToLinkableKeysMap) }>({ User, Invite })
implements UserTypes.IUserModuleService implements UserTypes.IUserModuleService
{ {
__joinerConfig(): ModuleJoinerConfig { __joinerConfig(): ModuleJoinerConfig {
@@ -1,11 +1,3 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.WORKFLOW_ENGINE) export const joinerConfig = defineJoinerConfig(Modules.WORKFLOW_ENGINE)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -17,7 +17,7 @@ import type {
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { WorkflowExecution } from "@models" import { WorkflowExecution } from "@models"
import { WorkflowOrchestratorService } from "@services" import { WorkflowOrchestratorService } from "@services"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
@@ -29,7 +29,7 @@ export class WorkflowsModuleService<
TWorkflowExecution extends WorkflowExecution = WorkflowExecution TWorkflowExecution extends WorkflowExecution = WorkflowExecution
> extends ModulesSdkUtils.MedusaService<{ > extends ModulesSdkUtils.MedusaService<{
WorkflowExecution: { dto: WorkflowExecution } WorkflowExecution: { dto: WorkflowExecution }
}>({ WorkflowExecution }, entityNameToLinkableKeysMap) { }>({ WorkflowExecution }) {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
protected workflowExecutionService_: ModulesSdkTypes.IMedusaInternalService<TWorkflowExecution> protected workflowExecutionService_: ModulesSdkTypes.IMedusaInternalService<TWorkflowExecution>
protected workflowOrchestratorService_: WorkflowOrchestratorService protected workflowOrchestratorService_: WorkflowOrchestratorService
@@ -1,11 +1,3 @@
import { import { defineJoinerConfig, Modules } from "@medusajs/utils"
buildEntitiesNameToLinkableKeysMap,
defineJoinerConfig,
MapToConfig,
Modules,
} from "@medusajs/utils"
export const joinerConfig = defineJoinerConfig(Modules.WORKFLOW_ENGINE) export const joinerConfig = defineJoinerConfig(Modules.WORKFLOW_ENGINE)
export const entityNameToLinkableKeysMap: MapToConfig =
buildEntitiesNameToLinkableKeysMap(joinerConfig.linkableKeys)
@@ -17,7 +17,7 @@ import type {
} from "@medusajs/workflows-sdk" } from "@medusajs/workflows-sdk"
import { WorkflowExecution } from "@models" import { WorkflowExecution } from "@models"
import { WorkflowOrchestratorService } from "@services" import { WorkflowOrchestratorService } from "@services"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config" import { joinerConfig } from "../joiner-config"
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
@@ -30,7 +30,7 @@ export class WorkflowsModuleService<
TWorkflowExecution extends WorkflowExecution = WorkflowExecution TWorkflowExecution extends WorkflowExecution = WorkflowExecution
> extends ModulesSdkUtils.MedusaService<{ > extends ModulesSdkUtils.MedusaService<{
WorkflowExecution: { dto: WorkflowExecution } WorkflowExecution: { dto: WorkflowExecution }
}>({ WorkflowExecution }, entityNameToLinkableKeysMap) { }>({ WorkflowExecution }) {
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
protected workflowExecutionService_: ModulesSdkTypes.IMedusaInternalService<TWorkflowExecution> protected workflowExecutionService_: ModulesSdkTypes.IMedusaInternalService<TWorkflowExecution>
protected workflowOrchestratorService_: WorkflowOrchestratorService protected workflowOrchestratorService_: WorkflowOrchestratorService