diff --git a/.changeset/late-insects-punch.md b/.changeset/late-insects-punch.md new file mode 100644 index 0000000000..5ec64f7959 --- /dev/null +++ b/.changeset/late-insects-punch.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +fix(medusa): model loader with customizations diff --git a/packages/medusa/src/loaders/__tests__/models.spec.ts b/packages/medusa/src/loaders/__tests__/models.spec.ts index 7d38ae836c..7ec8e5af54 100644 --- a/packages/medusa/src/loaders/__tests__/models.spec.ts +++ b/packages/medusa/src/loaders/__tests__/models.spec.ts @@ -12,7 +12,7 @@ describe("models loader", () => { beforeAll(async () => { try { - models = await modelsLoader({ + models = modelsLoader({ container, isTest: true, coreTestPathGlob: "../models/{product,product-variant}.ts", @@ -30,9 +30,9 @@ describe("models loader", () => { }) it("ensure that the product model is an extended model", () => { - const productModel = models.find((model) => model.name === "Product") + const productModel = container.resolve("productModel") - expect(new productModel().custom_attribute).toEqual("test") + expect(productModel.custom_attribute).toEqual("test") }) it("ensure that the extended product model is registered in db_entities", () => { diff --git a/packages/medusa/src/loaders/models.ts b/packages/medusa/src/loaders/models.ts index 8d7ac29087..aba6c9d22a 100644 --- a/packages/medusa/src/loaders/models.ts +++ b/packages/medusa/src/loaders/models.ts @@ -8,6 +8,7 @@ import path from "path" import { ClassConstructor, MedusaContainer } from "../types/global" import { EntitySchema } from "typeorm" import { asClass, asValue } from "awilix" +import { upperCaseFirst } from "@medusajs/utils" type ModelLoaderParams = { container: MedusaContainer @@ -62,8 +63,9 @@ export default ( // If an extension file is found, override it with that instead if (mappedExtensionModel) { const coreModel = require(modelPath) - const modelName = + const modelName = upperCaseFirst( formatRegistrationNameWithoutNamespace(modelPath) + ) coreModel[modelName] = mappedExtensionModel val = mappedExtensionModel diff --git a/packages/medusa/src/loaders/plugins.ts b/packages/medusa/src/loaders/plugins.ts index 96301ad671..de6df5f2e3 100644 --- a/packages/medusa/src/loaders/plugins.ts +++ b/packages/medusa/src/loaders/plugins.ts @@ -1,4 +1,4 @@ -import { SearchUtils } from "@medusajs/utils" +import { SearchUtils, upperCaseFirst } from "@medusajs/utils" import { aliasTo, asFunction, asValue, Lifetime } from "awilix" import { Express } from "express" import fs from "fs" @@ -100,7 +100,7 @@ export default async ({ function getResolvedPlugins( rootDirectory: string, configModule: ConfigModule, - extensionDirectoryPath: string = 'dist' + extensionDirectoryPath = "dist" ): undefined | PluginDetails[] { const { plugins } = configModule @@ -132,8 +132,8 @@ export async function registerPluginModels({ rootDirectory, container, configModule, - extensionDirectoryPath = 'dist', - pathGlob = "/models/*.js" + extensionDirectoryPath = "dist", + pathGlob = "/models/*.js", }: { rootDirectory: string container: MedusaContainer @@ -141,20 +141,13 @@ export async function registerPluginModels({ extensionDirectoryPath?: string pathGlob?: string }): Promise { - const resolved = getResolvedPlugins( - rootDirectory, - configModule, - extensionDirectoryPath - ) || [] + const resolved = + getResolvedPlugins(rootDirectory, configModule, extensionDirectoryPath) || + [] await Promise.all( resolved.map(async (pluginDetails) => { - registerModels( - pluginDetails, - container, - rootDirectory, - pathGlob, - ) + registerModels(pluginDetails, container, rootDirectory, pathGlob) }) ) } @@ -579,57 +572,74 @@ function registerRepositories( * version, id, resolved path, etc. See resolvePlugin * @param {object} container - the container where the services will be * registered + * @param rootDirectory + * @param pathGlob * @return {void} */ function registerModels( pluginDetails: PluginDetails, container: MedusaContainer, rootDirectory: string, - pathGlob: string = "/models/*.js" + pathGlob = "/models/*.js" ): void { - const pluginFullPathGlob = path.join(pluginDetails.resolve, pathGlob) + const pluginFullPathGlob = path.join(pluginDetails.resolve, pathGlob) const modelExtensionsMap = getModelExtensionsMap({ - directory: rootDirectory, + directory: pluginDetails.resolve, pathGlob: pathGlob, config: { register: true }, }) - const coreOrPluginModelsPath = glob.sync( - pluginFullPathGlob, - { ignore: ["index.js", "index.js.map"] } - ) + const pluginModels = glob.sync(pluginFullPathGlob, { + ignore: ["index.js", "index.js.map"], + }) - coreOrPluginModelsPath.forEach((coreOrPluginModelPath) => { + const coreModelsFullGlob = path.join(__dirname, "../models/*.js") + const coreModels = glob.sync(coreModelsFullGlob, { + cwd: __dirname, + ignore: ["index.js", "index.ts", "index.js.map"], + }) + + // Apply the extended models to the core models first to ensure that + // when relationships are created, the extended models are used + coreModels.forEach((modelPath) => { + const loaded = require(modelPath) as + | ClassConstructor + | EntitySchema + + if (loaded) { + const name = formatRegistrationName(modelPath) + const mappedExtensionModel = modelExtensionsMap.get(name) + if (mappedExtensionModel) { + const modelName = upperCaseFirst( + formatRegistrationNameWithoutNamespace(modelPath) + ) + + loaded[modelName] = mappedExtensionModel + } + } + }) + + pluginModels.forEach((coreOrPluginModelPath) => { const loaded = require(coreOrPluginModelPath) as | ClassConstructor | EntitySchema - Object.entries(loaded).map( - ([, val]: [string, ClassConstructor | EntitySchema]) => { - if (typeof val === "function" || val instanceof EntitySchema) { - const name = formatRegistrationName(coreOrPluginModelPath) - const mappedExtensionModel = modelExtensionsMap.get(name) + if (loaded) { + Object.entries(loaded).map( + ([, val]: [string, ClassConstructor | EntitySchema]) => { + if (typeof val === "function" || val instanceof EntitySchema) { + const name = formatRegistrationName(coreOrPluginModelPath) - // If an extension file is found, override it with that instead - if (mappedExtensionModel) { - const coreOrPluginModel = require(coreOrPluginModelPath) - const modelName = formatRegistrationNameWithoutNamespace( - coreOrPluginModelPath - ) + container.register({ + [name]: asValue(val), + }) - coreOrPluginModel[modelName] = mappedExtensionModel - val = mappedExtensionModel + container.registerAdd("db_entities", asValue(val)) } - - container.register({ - [name]: asValue(val), - }) - - container.registerAdd("db_entities", asValue(val)) } - } - ) + ) + } }) }