fix(medusa): model loader with customizations (#4443)

* fix(medusa): model loader with customizations

* fix plugin models loader

* Create late-insects-punch.md

* Address pr feedback

* remove unnecessary bits

* remove unnecessary bits

* fix

* remove unnecessary changes

* rm duplicate param jsdoc
This commit is contained in:
Adrien de Peretti
2023-07-04 11:34:19 +02:00
committed by GitHub
parent 417debfe7d
commit bdd9c5a7e9
4 changed files with 65 additions and 48 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---
fix(medusa): model loader with customizations
@@ -12,7 +12,7 @@ describe("models loader", () => {
beforeAll(async () => { beforeAll(async () => {
try { try {
models = await modelsLoader({ models = modelsLoader({
container, container,
isTest: true, isTest: true,
coreTestPathGlob: "../models/{product,product-variant}.ts", coreTestPathGlob: "../models/{product,product-variant}.ts",
@@ -30,9 +30,9 @@ describe("models loader", () => {
}) })
it("ensure that the product model is an extended model", () => { 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", () => { it("ensure that the extended product model is registered in db_entities", () => {
+3 -1
View File
@@ -8,6 +8,7 @@ import path from "path"
import { ClassConstructor, MedusaContainer } from "../types/global" import { ClassConstructor, MedusaContainer } from "../types/global"
import { EntitySchema } from "typeorm" import { EntitySchema } from "typeorm"
import { asClass, asValue } from "awilix" import { asClass, asValue } from "awilix"
import { upperCaseFirst } from "@medusajs/utils"
type ModelLoaderParams = { type ModelLoaderParams = {
container: MedusaContainer container: MedusaContainer
@@ -62,8 +63,9 @@ export default (
// If an extension file is found, override it with that instead // If an extension file is found, override it with that instead
if (mappedExtensionModel) { if (mappedExtensionModel) {
const coreModel = require(modelPath) const coreModel = require(modelPath)
const modelName = const modelName = upperCaseFirst(
formatRegistrationNameWithoutNamespace(modelPath) formatRegistrationNameWithoutNamespace(modelPath)
)
coreModel[modelName] = mappedExtensionModel coreModel[modelName] = mappedExtensionModel
val = mappedExtensionModel val = mappedExtensionModel
+54 -44
View File
@@ -1,4 +1,4 @@
import { SearchUtils } from "@medusajs/utils" import { SearchUtils, upperCaseFirst } from "@medusajs/utils"
import { aliasTo, asFunction, asValue, Lifetime } from "awilix" import { aliasTo, asFunction, asValue, Lifetime } from "awilix"
import { Express } from "express" import { Express } from "express"
import fs from "fs" import fs from "fs"
@@ -100,7 +100,7 @@ export default async ({
function getResolvedPlugins( function getResolvedPlugins(
rootDirectory: string, rootDirectory: string,
configModule: ConfigModule, configModule: ConfigModule,
extensionDirectoryPath: string = 'dist' extensionDirectoryPath = "dist"
): undefined | PluginDetails[] { ): undefined | PluginDetails[] {
const { plugins } = configModule const { plugins } = configModule
@@ -132,8 +132,8 @@ export async function registerPluginModels({
rootDirectory, rootDirectory,
container, container,
configModule, configModule,
extensionDirectoryPath = 'dist', extensionDirectoryPath = "dist",
pathGlob = "/models/*.js" pathGlob = "/models/*.js",
}: { }: {
rootDirectory: string rootDirectory: string
container: MedusaContainer container: MedusaContainer
@@ -141,20 +141,13 @@ export async function registerPluginModels({
extensionDirectoryPath?: string extensionDirectoryPath?: string
pathGlob?: string pathGlob?: string
}): Promise<void> { }): Promise<void> {
const resolved = getResolvedPlugins( const resolved =
rootDirectory, getResolvedPlugins(rootDirectory, configModule, extensionDirectoryPath) ||
configModule, []
extensionDirectoryPath
) || []
await Promise.all( await Promise.all(
resolved.map(async (pluginDetails) => { resolved.map(async (pluginDetails) => {
registerModels( registerModels(pluginDetails, container, rootDirectory, pathGlob)
pluginDetails,
container,
rootDirectory,
pathGlob,
)
}) })
) )
} }
@@ -579,57 +572,74 @@ function registerRepositories(
* version, id, resolved path, etc. See resolvePlugin * version, id, resolved path, etc. See resolvePlugin
* @param {object} container - the container where the services will be * @param {object} container - the container where the services will be
* registered * registered
* @param rootDirectory
* @param pathGlob
* @return {void} * @return {void}
*/ */
function registerModels( function registerModels(
pluginDetails: PluginDetails, pluginDetails: PluginDetails,
container: MedusaContainer, container: MedusaContainer,
rootDirectory: string, rootDirectory: string,
pathGlob: string = "/models/*.js" pathGlob = "/models/*.js"
): void { ): void {
const pluginFullPathGlob = path.join(pluginDetails.resolve, pathGlob) const pluginFullPathGlob = path.join(pluginDetails.resolve, pathGlob)
const modelExtensionsMap = getModelExtensionsMap({ const modelExtensionsMap = getModelExtensionsMap({
directory: rootDirectory, directory: pluginDetails.resolve,
pathGlob: pathGlob, pathGlob: pathGlob,
config: { register: true }, config: { register: true },
}) })
const coreOrPluginModelsPath = glob.sync( const pluginModels = glob.sync(pluginFullPathGlob, {
pluginFullPathGlob, ignore: ["index.js", "index.js.map"],
{ 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<unknown>
| 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 const loaded = require(coreOrPluginModelPath) as
| ClassConstructor<unknown> | ClassConstructor<unknown>
| EntitySchema | EntitySchema
Object.entries(loaded).map( if (loaded) {
([, val]: [string, ClassConstructor<unknown> | EntitySchema]) => { Object.entries(loaded).map(
if (typeof val === "function" || val instanceof EntitySchema) { ([, val]: [string, ClassConstructor<unknown> | EntitySchema]) => {
const name = formatRegistrationName(coreOrPluginModelPath) if (typeof val === "function" || val instanceof EntitySchema) {
const mappedExtensionModel = modelExtensionsMap.get(name) const name = formatRegistrationName(coreOrPluginModelPath)
// If an extension file is found, override it with that instead container.register({
if (mappedExtensionModel) { [name]: asValue(val),
const coreOrPluginModel = require(coreOrPluginModelPath) })
const modelName = formatRegistrationNameWithoutNamespace(
coreOrPluginModelPath
)
coreOrPluginModel[modelName] = mappedExtensionModel container.registerAdd("db_entities", asValue(val))
val = mappedExtensionModel
} }
container.register({
[name]: asValue(val),
})
container.registerAdd("db_entities", asValue(val))
} }
} )
) }
}) })
} }