Feat: Improvements to the migrations CLI and workflow (#8060)
This commit is contained in:
@@ -170,13 +170,18 @@ function buildLocalCommands(cli, isLocalProject) {
|
|||||||
),
|
),
|
||||||
})
|
})
|
||||||
.command({
|
.command({
|
||||||
command: `migrations [action]`,
|
command: `migrations [action] [modules...]`,
|
||||||
desc: `Manage migrations from the core and your own project`,
|
desc: `Manage migrations from the core and your own project`,
|
||||||
builder: {
|
builder: {
|
||||||
action: {
|
action: {
|
||||||
demand: true,
|
demand: true,
|
||||||
|
description: "The action to perform on migrations",
|
||||||
choices: ["run", "revert", "show"],
|
choices: ["run", "revert", "show"],
|
||||||
},
|
},
|
||||||
|
modules: {
|
||||||
|
description: "Revert migrations for defined modules",
|
||||||
|
demand: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
handler: handlerP(
|
handler: handlerP(
|
||||||
getCommandHandler(`migrate`, (args, cmd) => {
|
getCommandHandler(`migrate`, (args, cmd) => {
|
||||||
|
|||||||
@@ -180,7 +180,6 @@ export async function loadModuleMigrations(
|
|||||||
let runMigrations = loadedModule.runMigrations
|
let runMigrations = loadedModule.runMigrations
|
||||||
let revertMigration = loadedModule.revertMigration
|
let revertMigration = loadedModule.revertMigration
|
||||||
|
|
||||||
// Generate migration scripts if they are not present
|
|
||||||
if (!runMigrations || !revertMigration) {
|
if (!runMigrations || !revertMigration) {
|
||||||
const moduleResources = await loadResources(
|
const moduleResources = await loadResources(
|
||||||
resolution,
|
resolution,
|
||||||
@@ -190,8 +189,7 @@ export async function loadModuleMigrations(
|
|||||||
|
|
||||||
const migrationScriptOptions = {
|
const migrationScriptOptions = {
|
||||||
moduleName: resolution.definition.key,
|
moduleName: resolution.definition.key,
|
||||||
models: moduleResources.models,
|
pathToMigrations: join(moduleResources.normalizedPath, "migrations"),
|
||||||
pathToMigrations: moduleResources.normalizedPath + "/migrations",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
runMigrations ??= ModulesSdkUtils.buildMigrationScript(
|
runMigrations ??= ModulesSdkUtils.buildMigrationScript(
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import type {
|
|||||||
LoadedModule,
|
LoadedModule,
|
||||||
Logger,
|
Logger,
|
||||||
MedusaContainer,
|
MedusaContainer,
|
||||||
|
ModuleBootstrapDeclaration,
|
||||||
ModuleDefinition,
|
ModuleDefinition,
|
||||||
ModuleExports,
|
ModuleExports,
|
||||||
ModuleJoinerConfig,
|
ModuleJoinerConfig,
|
||||||
@@ -21,6 +22,7 @@ import {
|
|||||||
createMedusaContainer,
|
createMedusaContainer,
|
||||||
isObject,
|
isObject,
|
||||||
isString,
|
isString,
|
||||||
|
MedusaError,
|
||||||
ModuleRegistrationName,
|
ModuleRegistrationName,
|
||||||
Modules,
|
Modules,
|
||||||
ModulesSdkUtils,
|
ModulesSdkUtils,
|
||||||
@@ -47,10 +49,8 @@ declare module "@medusajs/types" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RunMigrationFn = (
|
export type RunMigrationFn = () => Promise<void>
|
||||||
options?: ModuleServiceInitializeOptions,
|
export type RevertMigrationFn = (moduleNames: string[]) => Promise<void>
|
||||||
injectedDependencies?: Record<any, any>
|
|
||||||
) => Promise<void>
|
|
||||||
|
|
||||||
export type MedusaModuleConfig = {
|
export type MedusaModuleConfig = {
|
||||||
[key: string | Modules]:
|
[key: string | Modules]:
|
||||||
@@ -176,11 +176,11 @@ async function initializeLinks({
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn("Error initializing link modules.", err)
|
console.warn("Error initializing link modules.", err)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
remoteLink: undefined,
|
remoteLink: undefined,
|
||||||
linkResolution: undefined,
|
linkResolution: undefined,
|
||||||
runMigrations: undefined,
|
runMigrations: () => void 0,
|
||||||
|
revertMigrations: () => void 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,7 +224,7 @@ export type MedusaAppOutput = {
|
|||||||
entitiesMap?: Record<string, any>
|
entitiesMap?: Record<string, any>
|
||||||
notFound?: Record<string, Record<string, string>>
|
notFound?: Record<string, Record<string, string>>
|
||||||
runMigrations: RunMigrationFn
|
runMigrations: RunMigrationFn
|
||||||
revertMigrations: RunMigrationFn
|
revertMigrations: RevertMigrationFn
|
||||||
onApplicationShutdown: () => Promise<void>
|
onApplicationShutdown: () => Promise<void>
|
||||||
onApplicationPrepareShutdown: () => Promise<void>
|
onApplicationPrepareShutdown: () => Promise<void>
|
||||||
sharedContainer?: MedusaContainer
|
sharedContainer?: MedusaContainer
|
||||||
@@ -317,10 +317,12 @@ async function MedusaApp_({
|
|||||||
delete modules[LinkModulePackage]
|
delete modules[LinkModulePackage]
|
||||||
delete modules[Modules.LINK]
|
delete modules[Modules.LINK]
|
||||||
|
|
||||||
let linkModuleOptions = {}
|
let linkModuleOrOptions:
|
||||||
|
| Partial<ModuleServiceInitializeOptions>
|
||||||
|
| Partial<ModuleBootstrapDeclaration> = {}
|
||||||
|
|
||||||
if (isObject(linkModule)) {
|
if (isObject(linkModule)) {
|
||||||
linkModuleOptions = linkModule
|
linkModuleOrOptions = linkModule
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const injectedDependency of Object.keys(injectedDependencies)) {
|
for (const injectedDependency of Object.keys(injectedDependencies)) {
|
||||||
@@ -380,7 +382,7 @@ async function MedusaApp_({
|
|||||||
runMigrations: linkModuleMigration,
|
runMigrations: linkModuleMigration,
|
||||||
revertMigrations: revertLinkModuleMigration,
|
revertMigrations: revertLinkModuleMigration,
|
||||||
} = await initializeLinks({
|
} = await initializeLinks({
|
||||||
config: linkModuleOptions,
|
config: linkModuleOrOptions,
|
||||||
linkModules,
|
linkModules,
|
||||||
injectedDependencies,
|
injectedDependencies,
|
||||||
moduleExports: isMedusaModule(linkModule) ? linkModule : undefined,
|
moduleExports: isMedusaModule(linkModule) ? linkModule : undefined,
|
||||||
@@ -402,10 +404,38 @@ async function MedusaApp_({
|
|||||||
return await remoteQuery.query(query, variables, options)
|
return await remoteQuery.query(query, variables, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
const applyMigration = async (linkModuleOptions, revert = false) => {
|
const applyMigration = async ({
|
||||||
for (const moduleName of Object.keys(allModules)) {
|
modulesNames,
|
||||||
const moduleResolution = MedusaModule.getModuleResolutions(moduleName)
|
revert = false,
|
||||||
|
}: {
|
||||||
|
modulesNames: string[]
|
||||||
|
revert?: boolean
|
||||||
|
}) => {
|
||||||
|
const moduleResolutions = modulesNames.map((moduleName) => {
|
||||||
|
return {
|
||||||
|
moduleName,
|
||||||
|
resolution: MedusaModule.getModuleResolutions(moduleName),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const missingModules = moduleResolutions
|
||||||
|
.filter(({ resolution }) => !resolution)
|
||||||
|
.map(({ moduleName }) => moduleName)
|
||||||
|
|
||||||
|
if (missingModules.length) {
|
||||||
|
const action = revert ? "revert" : "run"
|
||||||
|
const error = new MedusaError(
|
||||||
|
MedusaError.Types.UNKNOWN_MODULES,
|
||||||
|
`Cannot ${action} migrations for unknown module(s) ${missingModules.join(
|
||||||
|
","
|
||||||
|
)}`,
|
||||||
|
MedusaError.Codes.UNKNOWN_MODULES
|
||||||
|
)
|
||||||
|
error["allModules"] = Object.keys(allModules)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const { resolution: moduleResolution } of moduleResolutions) {
|
||||||
if (!moduleResolution.options?.database) {
|
if (!moduleResolution.options?.database) {
|
||||||
moduleResolution.options ??= {}
|
moduleResolution.options ??= {}
|
||||||
moduleResolution.options.database = {
|
moduleResolution.options.database = {
|
||||||
@@ -417,6 +447,7 @@ async function MedusaApp_({
|
|||||||
await MedusaModule.migrateDown(
|
await MedusaModule.migrateDown(
|
||||||
moduleResolution.definition.key,
|
moduleResolution.definition.key,
|
||||||
moduleResolution.resolutionPath as string,
|
moduleResolution.resolutionPath as string,
|
||||||
|
sharedContainer,
|
||||||
moduleResolution.options,
|
moduleResolution.options,
|
||||||
moduleResolution.moduleExports
|
moduleResolution.moduleExports
|
||||||
)
|
)
|
||||||
@@ -424,48 +455,65 @@ async function MedusaApp_({
|
|||||||
await MedusaModule.migrateUp(
|
await MedusaModule.migrateUp(
|
||||||
moduleResolution.definition.key,
|
moduleResolution.definition.key,
|
||||||
moduleResolution.resolutionPath as string,
|
moduleResolution.resolutionPath as string,
|
||||||
|
sharedContainer,
|
||||||
moduleResolution.options,
|
moduleResolution.options,
|
||||||
moduleResolution.moduleExports
|
moduleResolution.moduleExports
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const linkModuleOpt = { ...(linkModuleOptions ?? {}) }
|
|
||||||
linkModuleOpt.database ??= {
|
|
||||||
...(sharedResourcesConfig?.database ?? {}),
|
|
||||||
}
|
|
||||||
|
|
||||||
if (revert) {
|
|
||||||
revertLinkModuleMigration &&
|
|
||||||
(await revertLinkModuleMigration(
|
|
||||||
{
|
|
||||||
options: linkModuleOpt,
|
|
||||||
injectedDependencies,
|
|
||||||
},
|
|
||||||
linkModules
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
linkModuleMigration &&
|
|
||||||
(await linkModuleMigration(
|
|
||||||
{
|
|
||||||
options: linkModuleOpt,
|
|
||||||
injectedDependencies,
|
|
||||||
},
|
|
||||||
linkModules
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const runMigrations: RunMigrationFn = async (
|
const runMigrations: RunMigrationFn = async (): Promise<void> => {
|
||||||
linkModuleOptions
|
await applyMigration({
|
||||||
): Promise<void> => {
|
modulesNames: Object.keys(allModules),
|
||||||
await applyMigration(linkModuleOptions)
|
})
|
||||||
|
|
||||||
|
const options: Partial<ModuleServiceInitializeOptions> =
|
||||||
|
"scope" in linkModuleOrOptions
|
||||||
|
? { ...linkModuleOrOptions.options }
|
||||||
|
: {
|
||||||
|
...(linkModuleOrOptions as Partial<ModuleServiceInitializeOptions>),
|
||||||
|
}
|
||||||
|
|
||||||
|
options.database ??= {
|
||||||
|
...sharedResourcesConfig?.database,
|
||||||
|
}
|
||||||
|
|
||||||
|
await linkModuleMigration(
|
||||||
|
{
|
||||||
|
options,
|
||||||
|
injectedDependencies,
|
||||||
|
},
|
||||||
|
linkModules
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const revertMigrations: RunMigrationFn = async (
|
const revertMigrations: RevertMigrationFn = async (
|
||||||
linkModuleOptions
|
modulesNames
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
await applyMigration(linkModuleOptions, true)
|
await applyMigration({
|
||||||
|
modulesNames,
|
||||||
|
revert: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const options: Partial<ModuleServiceInitializeOptions> =
|
||||||
|
"scope" in linkModuleOrOptions
|
||||||
|
? { ...linkModuleOrOptions.options }
|
||||||
|
: {
|
||||||
|
...(linkModuleOrOptions as Partial<ModuleServiceInitializeOptions>),
|
||||||
|
}
|
||||||
|
|
||||||
|
options.database ??= {
|
||||||
|
...sharedResourcesConfig?.database,
|
||||||
|
}
|
||||||
|
|
||||||
|
await revertLinkModuleMigration(
|
||||||
|
{
|
||||||
|
options,
|
||||||
|
injectedDependencies,
|
||||||
|
},
|
||||||
|
linkModules
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -506,6 +554,7 @@ export async function MedusaAppMigrateUp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function MedusaAppMigrateDown(
|
export async function MedusaAppMigrateDown(
|
||||||
|
moduleNames: string[],
|
||||||
options: MedusaAppOptions = {}
|
options: MedusaAppOptions = {}
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const migrationOnly = true
|
const migrationOnly = true
|
||||||
@@ -515,5 +564,5 @@ export async function MedusaAppMigrateDown(
|
|||||||
migrationOnly,
|
migrationOnly,
|
||||||
})
|
})
|
||||||
|
|
||||||
await revertMigrations().finally(MedusaModule.clearInstances)
|
await revertMigrations(moduleNames).finally(MedusaModule.clearInstances)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
ModuleResolution,
|
ModuleResolution,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
createMedusaContainer,
|
createMedusaContainer,
|
||||||
promiseAll,
|
promiseAll,
|
||||||
simpleHash,
|
simpleHash,
|
||||||
@@ -344,7 +345,9 @@ class MedusaModule {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const logger_ =
|
const logger_ =
|
||||||
container.resolve("logger", { allowUnregistered: true }) ?? logger
|
container.resolve(ContainerRegistrationKeys.LOGGER, {
|
||||||
|
allowUnregistered: true,
|
||||||
|
}) ?? logger
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await moduleLoader({
|
await moduleLoader({
|
||||||
@@ -475,7 +478,9 @@ class MedusaModule {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const logger_ =
|
const logger_ =
|
||||||
container.resolve("logger", { allowUnregistered: true }) ?? logger
|
container.resolve(ContainerRegistrationKeys.LOGGER, {
|
||||||
|
allowUnregistered: true,
|
||||||
|
}) ?? logger
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await moduleLoader({
|
await moduleLoader({
|
||||||
@@ -534,6 +539,7 @@ class MedusaModule {
|
|||||||
public static async migrateUp(
|
public static async migrateUp(
|
||||||
moduleKey: string,
|
moduleKey: string,
|
||||||
modulePath: string,
|
modulePath: string,
|
||||||
|
container?: MedusaContainer,
|
||||||
options?: Record<string, any>,
|
options?: Record<string, any>,
|
||||||
moduleExports?: ModuleExports
|
moduleExports?: ModuleExports
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -544,6 +550,11 @@ class MedusaModule {
|
|||||||
options,
|
options,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const logger_ =
|
||||||
|
container?.resolve(ContainerRegistrationKeys.LOGGER, {
|
||||||
|
allowUnregistered: true,
|
||||||
|
}) ?? logger
|
||||||
|
|
||||||
for (const mod in moduleResolutions) {
|
for (const mod in moduleResolutions) {
|
||||||
const [migrateUp] = await loadModuleMigrations(
|
const [migrateUp] = await loadModuleMigrations(
|
||||||
moduleResolutions[mod],
|
moduleResolutions[mod],
|
||||||
@@ -553,7 +564,7 @@ class MedusaModule {
|
|||||||
if (typeof migrateUp === "function") {
|
if (typeof migrateUp === "function") {
|
||||||
await migrateUp({
|
await migrateUp({
|
||||||
options,
|
options,
|
||||||
logger,
|
logger: logger_,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -562,6 +573,7 @@ class MedusaModule {
|
|||||||
public static async migrateDown(
|
public static async migrateDown(
|
||||||
moduleKey: string,
|
moduleKey: string,
|
||||||
modulePath: string,
|
modulePath: string,
|
||||||
|
container?: MedusaContainer,
|
||||||
options?: Record<string, any>,
|
options?: Record<string, any>,
|
||||||
moduleExports?: ModuleExports
|
moduleExports?: ModuleExports
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -572,6 +584,11 @@ class MedusaModule {
|
|||||||
options,
|
options,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const logger_ =
|
||||||
|
container?.resolve(ContainerRegistrationKeys.LOGGER, {
|
||||||
|
allowUnregistered: true,
|
||||||
|
}) ?? logger
|
||||||
|
|
||||||
for (const mod in moduleResolutions) {
|
for (const mod in moduleResolutions) {
|
||||||
const [, migrateDown] = await loadModuleMigrations(
|
const [, migrateDown] = await loadModuleMigrations(
|
||||||
moduleResolutions[mod],
|
moduleResolutions[mod],
|
||||||
@@ -581,7 +598,7 @@ class MedusaModule {
|
|||||||
if (typeof migrateDown === "function") {
|
if (typeof migrateDown === "function") {
|
||||||
await migrateDown({
|
await migrateDown({
|
||||||
options,
|
options,
|
||||||
logger,
|
logger: logger_,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ export const MedusaErrorTypes = {
|
|||||||
NOT_ALLOWED: "not_allowed",
|
NOT_ALLOWED: "not_allowed",
|
||||||
UNEXPECTED_STATE: "unexpected_state",
|
UNEXPECTED_STATE: "unexpected_state",
|
||||||
CONFLICT: "conflict",
|
CONFLICT: "conflict",
|
||||||
|
UNKNOWN_MODULES: "unknown_modules",
|
||||||
PAYMENT_AUTHORIZATION_ERROR: "payment_authorization_error",
|
PAYMENT_AUTHORIZATION_ERROR: "payment_authorization_error",
|
||||||
PAYMENT_REQUIRES_MORE_ERROR: "payment_requires_more_error",
|
PAYMENT_REQUIRES_MORE_ERROR: "payment_requires_more_error",
|
||||||
}
|
}
|
||||||
@@ -20,6 +21,7 @@ export const MedusaErrorTypes = {
|
|||||||
export const MedusaErrorCodes = {
|
export const MedusaErrorCodes = {
|
||||||
INSUFFICIENT_INVENTORY: "insufficient_inventory",
|
INSUFFICIENT_INVENTORY: "insufficient_inventory",
|
||||||
CART_INCOMPATIBLE_STATE: "cart_incompatible_state",
|
CART_INCOMPATIBLE_STATE: "cart_incompatible_state",
|
||||||
|
UNKNOWN_MODULES: "unknown_modules",
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
UmzugMigration,
|
UmzugMigration,
|
||||||
} from "@mikro-orm/migrations"
|
} from "@mikro-orm/migrations"
|
||||||
import { MikroORM, MikroORMOptions } from "@mikro-orm/core"
|
import { MikroORM, MikroORMOptions } from "@mikro-orm/core"
|
||||||
|
import { PostgreSqlDriver } from "@mikro-orm/postgresql"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Events emitted by the migrations class
|
* Events emitted by the migrations class
|
||||||
@@ -20,11 +21,13 @@ export type MigrationsEvents = {
|
|||||||
* Exposes the API to programmatically manage Mikro ORM migrations
|
* Exposes the API to programmatically manage Mikro ORM migrations
|
||||||
*/
|
*/
|
||||||
export class Migrations extends EventEmitter<MigrationsEvents> {
|
export class Migrations extends EventEmitter<MigrationsEvents> {
|
||||||
#config: Partial<MikroORMOptions>
|
#configOrConnection: Partial<MikroORMOptions> | MikroORM<PostgreSqlDriver>
|
||||||
|
|
||||||
constructor(config: Partial<MikroORMOptions>) {
|
constructor(
|
||||||
|
configOrConnection: Partial<MikroORMOptions> | MikroORM<PostgreSqlDriver>
|
||||||
|
) {
|
||||||
super()
|
super()
|
||||||
this.#config = config
|
this.#configOrConnection = configOrConnection
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,10 +35,14 @@ export class Migrations extends EventEmitter<MigrationsEvents> {
|
|||||||
* one
|
* one
|
||||||
*/
|
*/
|
||||||
async #getConnection() {
|
async #getConnection() {
|
||||||
|
if ("connect" in this.#configOrConnection) {
|
||||||
|
return this.#configOrConnection as MikroORM<PostgreSqlDriver>
|
||||||
|
}
|
||||||
|
|
||||||
return await MikroORM.init({
|
return await MikroORM.init({
|
||||||
...this.#config,
|
...this.#configOrConnection,
|
||||||
migrations: {
|
migrations: {
|
||||||
...this.#config.migrations,
|
...this.#configOrConnection.migrations,
|
||||||
silent: true,
|
silent: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types"
|
import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types"
|
||||||
|
|
||||||
import { EntitySchema } from "@mikro-orm/core"
|
|
||||||
import { upperCaseFirst } from "../../common"
|
|
||||||
import { mikroOrmCreateConnection } from "../../dal"
|
import { mikroOrmCreateConnection } from "../../dal"
|
||||||
import { DmlEntity, toMikroORMEntity } from "../../dml"
|
|
||||||
import { loadDatabaseConfig } from "../load-module-database-config"
|
import { loadDatabaseConfig } from "../load-module-database-config"
|
||||||
|
import { Migrations } from "../../migrations"
|
||||||
|
|
||||||
|
const TERMINAL_SIZE = process.stdout.columns
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility function to build a migration script that will revert the migrations.
|
* Utility function to build a migration script that will revert the migrations.
|
||||||
* Only used in mikro orm based modules.
|
* Only used in mikro orm based modules.
|
||||||
* @param moduleName
|
* @param moduleName
|
||||||
* @param models
|
|
||||||
* @param pathToMigrations
|
* @param pathToMigrations
|
||||||
*/
|
*/
|
||||||
export function buildRevertMigrationScript({
|
export function buildRevertMigrationScript({ moduleName, pathToMigrations }) {
|
||||||
moduleName,
|
|
||||||
models,
|
|
||||||
pathToMigrations,
|
|
||||||
}) {
|
|
||||||
/**
|
/**
|
||||||
* This script is only valid for mikro orm managers. If a user provide a custom manager
|
* This script is only valid for mikro orm managers. If a user provide a custom manager
|
||||||
* he is in charge of reverting the migrations.
|
* he is in charge of reverting the migrations.
|
||||||
@@ -34,34 +28,30 @@ export function buildRevertMigrationScript({
|
|||||||
> = {}) {
|
> = {}) {
|
||||||
logger ??= console as unknown as Logger
|
logger ??= console as unknown as Logger
|
||||||
|
|
||||||
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
|
console.log("")
|
||||||
|
logger.info(`MODULE: ${moduleName}`)
|
||||||
|
|
||||||
const dbData = loadDatabaseConfig(moduleName, options)!
|
const dbData = loadDatabaseConfig(moduleName, options)!
|
||||||
const entities = Object.values(models).map((model) => {
|
const orm = await mikroOrmCreateConnection(dbData, [], pathToMigrations)
|
||||||
if (DmlEntity.isDmlEntity(model)) {
|
const migrations = new Migrations(orm)
|
||||||
return toMikroORMEntity(model)
|
|
||||||
}
|
|
||||||
|
|
||||||
return model
|
migrations.on("reverting", (migration) => {
|
||||||
}) as unknown as EntitySchema[]
|
logger.info(` ● Reverting ${migration.name}`)
|
||||||
|
})
|
||||||
const orm = await mikroOrmCreateConnection(
|
migrations.on("reverted", (migration) => {
|
||||||
dbData,
|
logger.info(` ✔ Reverted ${migration.name}`)
|
||||||
entities,
|
})
|
||||||
pathToMigrations
|
|
||||||
)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const migrator = orm.getMigrator()
|
const result = await migrations.revert()
|
||||||
await migrator.down()
|
if (result.length) {
|
||||||
|
logger.info("Reverted successfully")
|
||||||
logger?.info(`${upperCaseFirst(moduleName)} module migration executed`)
|
} else {
|
||||||
|
logger.info("Skipped. Nothing to revert")
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger?.error(
|
logger.error(`Failed with error ${error.message}`, error)
|
||||||
`${upperCaseFirst(
|
|
||||||
moduleName
|
|
||||||
)} module migration failed to run - Error: ${error.errros ?? error}`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await orm.close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types"
|
import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types"
|
||||||
import { EntitySchema } from "@mikro-orm/core"
|
|
||||||
import { upperCaseFirst } from "../../common"
|
|
||||||
import { mikroOrmCreateConnection } from "../../dal"
|
import { mikroOrmCreateConnection } from "../../dal"
|
||||||
import { DmlEntity, toMikroORMEntity } from "../../dml"
|
|
||||||
import { loadDatabaseConfig } from "../load-module-database-config"
|
import { loadDatabaseConfig } from "../load-module-database-config"
|
||||||
|
import { Migrations } from "../../migrations"
|
||||||
|
|
||||||
|
const TERMINAL_SIZE = process.stdout.columns
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility function to build a migration script that will run the migrations.
|
* Utility function to build a migration script that will run the migrations.
|
||||||
* Only used in mikro orm based modules.
|
* Only used in mikro orm based modules.
|
||||||
* @param moduleName
|
* @param moduleName
|
||||||
* @param models
|
|
||||||
* @param pathToMigrations
|
* @param pathToMigrations
|
||||||
*/
|
*/
|
||||||
export function buildMigrationScript({ moduleName, models, pathToMigrations }) {
|
export function buildMigrationScript({ moduleName, pathToMigrations }) {
|
||||||
/**
|
/**
|
||||||
* This script is only valid for mikro orm managers. If a user provide a custom manager
|
* This script is only valid for mikro orm managers. If a user provide a custom manager
|
||||||
* he is in charge of running the migrations.
|
* he is in charge of running the migrations.
|
||||||
@@ -29,48 +28,30 @@ export function buildMigrationScript({ moduleName, models, pathToMigrations }) {
|
|||||||
> = {}) {
|
> = {}) {
|
||||||
logger ??= console as unknown as Logger
|
logger ??= console as unknown as Logger
|
||||||
|
|
||||||
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
|
console.log("")
|
||||||
|
logger.info(`MODULE: ${moduleName}`)
|
||||||
|
|
||||||
const dbData = loadDatabaseConfig(moduleName, options)!
|
const dbData = loadDatabaseConfig(moduleName, options)!
|
||||||
const entities = Object.values(models).map((model) => {
|
const orm = await mikroOrmCreateConnection(dbData, [], pathToMigrations)
|
||||||
if (DmlEntity.isDmlEntity(model)) {
|
const migrations = new Migrations(orm)
|
||||||
return toMikroORMEntity(model)
|
|
||||||
}
|
|
||||||
|
|
||||||
return model
|
migrations.on("migrating", (migration) => {
|
||||||
}) as unknown as EntitySchema[]
|
logger.info(` ● Migrating ${migration.name}`)
|
||||||
|
})
|
||||||
const orm = await mikroOrmCreateConnection(
|
migrations.on("migrated", (migration) => {
|
||||||
dbData,
|
logger.info(` ✔ Migrated ${migration.name}`)
|
||||||
entities,
|
})
|
||||||
pathToMigrations
|
|
||||||
)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const migrator = orm.getMigrator()
|
const result = await migrations.run()
|
||||||
const pendingMigrations = await migrator.getPendingMigrations()
|
if (result.length) {
|
||||||
|
logger.info("Completed successfully")
|
||||||
if (pendingMigrations.length) {
|
} else {
|
||||||
logger.info(
|
logger.info("Skipped. Database is upto-date")
|
||||||
`Pending migrations: ${JSON.stringify(pendingMigrations, null, 2)}`
|
|
||||||
)
|
|
||||||
|
|
||||||
await migrator.up({
|
|
||||||
migrations: pendingMigrations.map((m) => m.name),
|
|
||||||
})
|
|
||||||
|
|
||||||
logger.info(
|
|
||||||
`${upperCaseFirst(moduleName)} module: ${
|
|
||||||
pendingMigrations.length
|
|
||||||
} migration files executed`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(
|
logger.error(`Failed with error ${error.message}`, error)
|
||||||
`${upperCaseFirst(
|
|
||||||
moduleName
|
|
||||||
)} module migration failed to run - Error: ${error.errros ?? error}`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await orm.close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import Logger from "../loaders/logger"
|
import Logger from "../loaders/logger"
|
||||||
import { migrateMedusaApp, revertMedusaApp } from "../loaders/medusa-app"
|
import { migrateMedusaApp, revertMedusaApp } from "../loaders/medusa-app"
|
||||||
import { initializeContainer } from "../loaders"
|
import { initializeContainer } from "../loaders"
|
||||||
import { ContainerRegistrationKeys } from "@medusajs/utils"
|
import { ContainerRegistrationKeys, MedusaError } from "@medusajs/utils"
|
||||||
import { getResolvedPlugins } from "../loaders/helpers/resolve-plugins"
|
import { getResolvedPlugins } from "../loaders/helpers/resolve-plugins"
|
||||||
import { resolvePluginsLinks } from "../loaders/helpers/resolve-plugins-links"
|
import { resolvePluginsLinks } from "../loaders/helpers/resolve-plugins-links"
|
||||||
|
|
||||||
|
const TERMINAL_SIZE = process.stdout.columns
|
||||||
|
|
||||||
const main = async function ({ directory }) {
|
const main = async function ({ directory }) {
|
||||||
const args = process.argv
|
const args = process.argv
|
||||||
args.shift()
|
args.shift()
|
||||||
args.shift()
|
args.shift()
|
||||||
args.shift()
|
args.shift()
|
||||||
|
|
||||||
|
const action = args[0]
|
||||||
const container = await initializeContainer(directory)
|
const container = await initializeContainer(directory)
|
||||||
|
|
||||||
const configModule = container.resolve(
|
const configModule = container.resolve(
|
||||||
@@ -20,21 +23,55 @@ const main = async function ({ directory }) {
|
|||||||
const plugins = getResolvedPlugins(directory, configModule, true) || []
|
const plugins = getResolvedPlugins(directory, configModule, true) || []
|
||||||
const pluginLinks = await resolvePluginsLinks(plugins, container)
|
const pluginLinks = await resolvePluginsLinks(plugins, container)
|
||||||
|
|
||||||
if (args[0] === "run") {
|
if (action === "run") {
|
||||||
|
Logger.info("Running migrations...")
|
||||||
|
|
||||||
await migrateMedusaApp({
|
await migrateMedusaApp({
|
||||||
configModule,
|
configModule,
|
||||||
linkModules: pluginLinks,
|
linkModules: pluginLinks,
|
||||||
container,
|
container,
|
||||||
})
|
})
|
||||||
|
|
||||||
Logger.info("Migrations completed.")
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
|
Logger.info("Migrations completed")
|
||||||
process.exit()
|
process.exit()
|
||||||
} else if (args[0] === "revert") {
|
} else if (action === "revert") {
|
||||||
await revertMedusaApp({ configModule, linkModules: pluginLinks, container })
|
const modulesToRevert = args.slice(1)
|
||||||
|
if (!modulesToRevert.length) {
|
||||||
|
Logger.error(
|
||||||
|
"Please provide the modules for which you want to revert migrations"
|
||||||
|
)
|
||||||
|
Logger.error(`For example: "npx medusa migration revert <moduleName>"`)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
Logger.info("Migrations reverted.")
|
Logger.info("Reverting migrations...")
|
||||||
} else if (args[0] === "show") {
|
|
||||||
Logger.info("not supported")
|
try {
|
||||||
|
await revertMedusaApp({
|
||||||
|
modulesToRevert,
|
||||||
|
configModule,
|
||||||
|
linkModules: pluginLinks,
|
||||||
|
container,
|
||||||
|
})
|
||||||
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
|
Logger.info("Migrations reverted")
|
||||||
|
process.exit()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
|
if (error.code && error.code === MedusaError.Codes.UNKNOWN_MODULES) {
|
||||||
|
Logger.error(error.message)
|
||||||
|
const modulesList = error.allModules.map(
|
||||||
|
(name: string) => ` - ${name}`
|
||||||
|
)
|
||||||
|
Logger.error(`Available modules:\n${modulesList.join("\n")}`)
|
||||||
|
} else {
|
||||||
|
Logger.error(error.message, error)
|
||||||
|
}
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
} else if (action === "show") {
|
||||||
|
Logger.info("Action not supported yet")
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export function mergeDefaultModules(
|
|||||||
async function runMedusaAppMigrations({
|
async function runMedusaAppMigrations({
|
||||||
configModule,
|
configModule,
|
||||||
container,
|
container,
|
||||||
|
moduleNames,
|
||||||
revert = false,
|
revert = false,
|
||||||
linkModules,
|
linkModules,
|
||||||
}: {
|
}: {
|
||||||
@@ -69,8 +70,16 @@ async function runMedusaAppMigrations({
|
|||||||
}
|
}
|
||||||
linkModules?: MedusaAppOptions["linkModules"]
|
linkModules?: MedusaAppOptions["linkModules"]
|
||||||
container: MedusaContainer
|
container: MedusaContainer
|
||||||
revert?: boolean
|
} & (
|
||||||
}): Promise<void> {
|
| {
|
||||||
|
moduleNames?: never
|
||||||
|
revert: false
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
moduleNames: string[]
|
||||||
|
revert: true
|
||||||
|
}
|
||||||
|
)): Promise<void> {
|
||||||
const injectedDependencies = {
|
const injectedDependencies = {
|
||||||
[ContainerRegistrationKeys.PG_CONNECTION]: container.resolve(
|
[ContainerRegistrationKeys.PG_CONNECTION]: container.resolve(
|
||||||
ContainerRegistrationKeys.PG_CONNECTION
|
ContainerRegistrationKeys.PG_CONNECTION
|
||||||
@@ -93,7 +102,7 @@ async function runMedusaAppMigrations({
|
|||||||
const configModules = mergeDefaultModules(configModule.modules)
|
const configModules = mergeDefaultModules(configModule.modules)
|
||||||
|
|
||||||
if (revert) {
|
if (revert) {
|
||||||
await MedusaAppMigrateDown({
|
await MedusaAppMigrateDown(moduleNames!, {
|
||||||
modulesConfig: configModules,
|
modulesConfig: configModules,
|
||||||
sharedContainer: container,
|
sharedContainer: container,
|
||||||
linkModules,
|
linkModules,
|
||||||
@@ -111,6 +120,12 @@ async function runMedusaAppMigrations({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param configModule The config module
|
||||||
|
* @param linkModules Custom links from the plugins
|
||||||
|
* @param container The medusa container
|
||||||
|
*/
|
||||||
export async function migrateMedusaApp({
|
export async function migrateMedusaApp({
|
||||||
configModule,
|
configModule,
|
||||||
linkModules,
|
linkModules,
|
||||||
@@ -127,14 +142,25 @@ export async function migrateMedusaApp({
|
|||||||
configModule,
|
configModule,
|
||||||
container,
|
container,
|
||||||
linkModules,
|
linkModules,
|
||||||
|
revert: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param modulesToRevert An array of modules for which you want to revert
|
||||||
|
* migrations
|
||||||
|
* @param configModule The config module
|
||||||
|
* @param linkModules Custom links from the plugins
|
||||||
|
* @param container The medusa container
|
||||||
|
*/
|
||||||
export async function revertMedusaApp({
|
export async function revertMedusaApp({
|
||||||
|
modulesToRevert,
|
||||||
configModule,
|
configModule,
|
||||||
linkModules,
|
linkModules,
|
||||||
container,
|
container,
|
||||||
}: {
|
}: {
|
||||||
|
modulesToRevert: string[]
|
||||||
configModule: {
|
configModule: {
|
||||||
modules?: CommonTypes.ConfigModule["modules"]
|
modules?: CommonTypes.ConfigModule["modules"]
|
||||||
projectConfig: CommonTypes.ConfigModule["projectConfig"]
|
projectConfig: CommonTypes.ConfigModule["projectConfig"]
|
||||||
@@ -143,6 +169,7 @@ export async function revertMedusaApp({
|
|||||||
linkModules?: MedusaAppOptions["linkModules"]
|
linkModules?: MedusaAppOptions["linkModules"]
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
await runMedusaAppMigrations({
|
await runMedusaAppMigrations({
|
||||||
|
moduleNames: modulesToRevert,
|
||||||
configModule,
|
configModule,
|
||||||
container,
|
container,
|
||||||
revert: true,
|
revert: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user