feat(medusa): Run shared module migrations (#3109)
This commit is contained in:
committed by
GitHub
parent
0326d6cfa3
commit
f776ed234f
@@ -1,51 +1,73 @@
|
||||
import { createConnection } from "typeorm"
|
||||
import { getConfigFile } from "medusa-core-utils"
|
||||
import featureFlagLoader from "../loaders/feature-flags"
|
||||
import { handleConfigError } from "../loaders/config"
|
||||
import configModuleLoader from "../loaders/config"
|
||||
import Logger from "../loaders/logger"
|
||||
|
||||
import getMigrations from "./utils/get-migrations"
|
||||
import getMigrations, { getModuleSharedResources } from "./utils/get-migrations"
|
||||
|
||||
const t = async function ({ directory }) {
|
||||
const getDataSource = async (directory) => {
|
||||
const configModule = configModuleLoader(directory)
|
||||
|
||||
const featureFlagRouter = featureFlagLoader(configModule)
|
||||
|
||||
const { coreMigrations } = getMigrations(directory, featureFlagRouter)
|
||||
|
||||
const { migrations: moduleMigrations } = getModuleSharedResources(
|
||||
configModule,
|
||||
featureFlagRouter
|
||||
)
|
||||
|
||||
return await createConnection({
|
||||
type: configModule.projectConfig.database_type,
|
||||
url: configModule.projectConfig.database_url,
|
||||
extra: configModule.projectConfig.database_extra || {},
|
||||
schema: configModule.projectConfig.database_schema,
|
||||
migrations: coreMigrations.concat(moduleMigrations),
|
||||
logging: true,
|
||||
})
|
||||
}
|
||||
|
||||
const main = async function ({ directory }) {
|
||||
const args = process.argv
|
||||
args.shift()
|
||||
args.shift()
|
||||
args.shift()
|
||||
|
||||
const { configModule, error } = getConfigFile(directory, `medusa-config`)
|
||||
|
||||
if (error) {
|
||||
handleConfigError(error)
|
||||
}
|
||||
|
||||
const featureFlagRouter = featureFlagLoader(configModule)
|
||||
|
||||
const enabledMigrations = await getMigrations(directory, featureFlagRouter)
|
||||
|
||||
const connection = await createConnection({
|
||||
type: configModule.projectConfig.database_type,
|
||||
url: configModule.projectConfig.database_url,
|
||||
schema: configModule.projectConfig.database_schema,
|
||||
extra: configModule.projectConfig.database_extra || {},
|
||||
migrations: enabledMigrations,
|
||||
logging: true,
|
||||
})
|
||||
|
||||
if (args[0] === "run") {
|
||||
await connection.runMigrations()
|
||||
await connection.close()
|
||||
const dataSource = await getDataSource(directory)
|
||||
|
||||
await dataSource.runMigrations()
|
||||
await dataSource.close()
|
||||
Logger.info("Migrations completed.")
|
||||
process.exit()
|
||||
} else if (args[0] === "revert") {
|
||||
await connection.undoLastMigration({ transaction: "all" })
|
||||
await connection.close()
|
||||
const dataSource = await getDataSource(directory)
|
||||
|
||||
await dataSource.undoLastMigration({ transaction: "all" })
|
||||
await dataSource.close()
|
||||
Logger.info("Migrations reverted.")
|
||||
|
||||
process.exit()
|
||||
} else if (args[0] === "show") {
|
||||
const configModule = configModuleLoader(directory)
|
||||
|
||||
const featureFlagRouter = featureFlagLoader(configModule)
|
||||
|
||||
const { coreMigrations } = getMigrations(directory, featureFlagRouter)
|
||||
|
||||
const connection = await createConnection({
|
||||
type: configModule.projectConfig.database_type,
|
||||
url: configModule.projectConfig.database_url,
|
||||
extra: configModule.projectConfig.database_extra || {},
|
||||
schema: configModule.projectConfig.database_schema,
|
||||
migrations: coreMigrations,
|
||||
logging: true,
|
||||
})
|
||||
|
||||
const unapplied = await connection.showMigrations()
|
||||
await connection.close()
|
||||
process.exit(unapplied ? 1 : 0)
|
||||
}
|
||||
}
|
||||
|
||||
export default t
|
||||
export default main
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
} from "../services"
|
||||
import { ConfigModule } from "../types/global"
|
||||
import { CreateProductInput } from "../types/product"
|
||||
import getMigrations from "./utils/get-migrations"
|
||||
import getMigrations, { getModuleSharedResources } from "./utils/get-migrations"
|
||||
|
||||
type SeedOptions = {
|
||||
directory: string
|
||||
@@ -58,7 +58,12 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) {
|
||||
|
||||
const dbType = configModule.projectConfig.database_type
|
||||
if (migrate && dbType !== "sqlite") {
|
||||
const migrationDirs = await getMigrations(directory, featureFlagRouter)
|
||||
const { coreMigrations } = getMigrations(directory, featureFlagRouter)
|
||||
|
||||
const { migrations: moduleMigrations } = getModuleSharedResources(
|
||||
configModule,
|
||||
featureFlagRouter
|
||||
)
|
||||
|
||||
const connectionOptions = {
|
||||
type: configModule.projectConfig.database_type,
|
||||
@@ -66,7 +71,7 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) {
|
||||
schema: configModule.projectConfig.database_schema,
|
||||
url: configModule.projectConfig.database_url,
|
||||
extra: configModule.projectConfig.database_extra || {},
|
||||
migrations: migrationDirs,
|
||||
migrations: coreMigrations.concat(moduleMigrations),
|
||||
logging: true,
|
||||
} as ConnectionOptions
|
||||
|
||||
@@ -91,9 +96,15 @@ const seed = async function ({ directory, migrate, seedFile }: SeedOptions) {
|
||||
const regionService: RegionService = container.resolve("regionService")
|
||||
const productService: ProductService = container.resolve("productService")
|
||||
/* eslint-disable */
|
||||
const productVariantService: ProductVariantService = container.resolve("productVariantService")
|
||||
const shippingOptionService: ShippingOptionService = container.resolve("shippingOptionService")
|
||||
const shippingProfileService: ShippingProfileService = container.resolve("shippingProfileService")
|
||||
const productVariantService: ProductVariantService = container.resolve(
|
||||
"productVariantService"
|
||||
)
|
||||
const shippingOptionService: ShippingOptionService = container.resolve(
|
||||
"shippingOptionService"
|
||||
)
|
||||
const shippingProfileService: ShippingProfileService = container.resolve(
|
||||
"shippingProfileService"
|
||||
)
|
||||
/* eslint-enable */
|
||||
|
||||
await manager.transaction(async (tx) => {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { isString } from "lodash"
|
||||
import { sync as existsSync } from "fs-exists-cached"
|
||||
import { getConfigFile, createRequireFromPath } from "medusa-core-utils"
|
||||
import { handleConfigError } from "../../loaders/config"
|
||||
import logger from "../../loaders/logger"
|
||||
import registerModuleDefinitions from "../../loaders/module-definitions"
|
||||
|
||||
function createFileContentHash(path, files) {
|
||||
return path + files
|
||||
@@ -89,7 +89,37 @@ function resolvePlugin(pluginName) {
|
||||
}
|
||||
}
|
||||
|
||||
export default async (directory, featureFlagRouter) => {
|
||||
export function getInternalModules(configModule) {
|
||||
const modules = []
|
||||
|
||||
const moduleResolutions = registerModuleDefinitions(configModule)
|
||||
|
||||
for (const moduleResolution of Object.values(moduleResolutions)) {
|
||||
if (
|
||||
!moduleResolution.resolutionPath ||
|
||||
moduleResolution.moduleDeclaration.scope !== "internal"
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
let loadedModule = null
|
||||
try {
|
||||
loadedModule = require(moduleResolution.moduleDeclaration.resolve).default
|
||||
} catch (error) {
|
||||
console.log("Error loading Module", error)
|
||||
continue
|
||||
}
|
||||
|
||||
modules.push({
|
||||
moduleDeclaration: moduleResolution.moduleDeclaration,
|
||||
loadedModule,
|
||||
})
|
||||
}
|
||||
|
||||
return modules
|
||||
}
|
||||
|
||||
export default (directory, featureFlagRouter) => {
|
||||
const { configModule, error } = getConfigFile(directory, `medusa-config`)
|
||||
|
||||
if (error) {
|
||||
@@ -118,11 +148,11 @@ export default async (directory, featureFlagRouter) => {
|
||||
})
|
||||
|
||||
const migrationDirs = []
|
||||
const coreMigrations = path.resolve(
|
||||
const corePackageMigrations = path.resolve(
|
||||
path.join(__dirname, "..", "..", "migrations")
|
||||
)
|
||||
|
||||
migrationDirs.push(path.join(coreMigrations, "*.js"))
|
||||
migrationDirs.push(path.join(corePackageMigrations, "*.js"))
|
||||
|
||||
for (const p of resolved) {
|
||||
const exists = existsSync(`${p.resolve}/migrations`)
|
||||
@@ -131,9 +161,15 @@ export default async (directory, featureFlagRouter) => {
|
||||
}
|
||||
}
|
||||
|
||||
return getEnabledMigrations(migrationDirs, (flag) =>
|
||||
const isFeatureFlagEnabled = (flag) =>
|
||||
featureFlagRouter.isFeatureEnabled(flag)
|
||||
|
||||
const coreMigrations = getEnabledMigrations(
|
||||
migrationDirs,
|
||||
isFeatureFlagEnabled
|
||||
)
|
||||
|
||||
return { coreMigrations }
|
||||
}
|
||||
|
||||
export const getEnabledMigrations = (migrationDirs, isFlagEnabled) => {
|
||||
@@ -154,3 +190,66 @@ export const getEnabledMigrations = (migrationDirs, isFlagEnabled) => {
|
||||
})
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
export const getModuleMigrations = (configModule, isFlagEnabled) => {
|
||||
const loadedModules = getInternalModules(configModule)
|
||||
|
||||
const allModules = []
|
||||
|
||||
for (const loadedModule of loadedModules) {
|
||||
const mod = loadedModule.loadedModule
|
||||
|
||||
const isolatedMigrations = {}
|
||||
const moduleMigrations = (mod.migrations ?? [])
|
||||
.map((migrations) => {
|
||||
const all = []
|
||||
for (const migration of Object.values(migrations)) {
|
||||
// TODO: revisit how Modules export their migration entrypoints up/down
|
||||
if (["up", "down"].includes(migration.name)) {
|
||||
isolatedMigrations[migration.name] = migration
|
||||
} else if (
|
||||
typeof migration.featureFlag === "undefined" ||
|
||||
isFlagEnabled(migration.featureFlag)
|
||||
) {
|
||||
all.push(migration)
|
||||
}
|
||||
}
|
||||
return all
|
||||
})
|
||||
.flat()
|
||||
|
||||
allModules.push({
|
||||
moduleDeclaration: loadedModule.moduleDeclaration,
|
||||
models: mod.models ?? [],
|
||||
migrations: moduleMigrations,
|
||||
externalMigrations: isolatedMigrations,
|
||||
})
|
||||
}
|
||||
|
||||
return allModules
|
||||
}
|
||||
|
||||
export const getModuleSharedResources = (configModule, featureFlagsRouter) => {
|
||||
const isFlagEnabled = (flag) =>
|
||||
featureFlagsRouter && featureFlagsRouter.isFeatureEnabled(flag)
|
||||
|
||||
const loadedModules = getModuleMigrations(configModule, isFlagEnabled)
|
||||
|
||||
let migrations = []
|
||||
let models = []
|
||||
|
||||
for (const mod of loadedModules) {
|
||||
if (mod.moduleDeclaration.resources !== "shared") {
|
||||
continue
|
||||
}
|
||||
|
||||
migrations = migrations.concat(mod.migrations)
|
||||
|
||||
models = models.concat(mod.models ?? [])
|
||||
}
|
||||
|
||||
return {
|
||||
models,
|
||||
migrations,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user