feat(migrations): CLI generate command (#8103)
This commit is contained in:
1 parent
4c2e9a3239
commit
104b00d4e9
14 files changed
+336
-159
No files matched your search
@@ -11,7 +11,9 @@ const { dropDatabase } = require("pg-god")
|
|||||||
const { DataSource } = require("typeorm")
|
const { DataSource } = require("typeorm")
|
||||||
const dbFactory = require("./use-template-db")
|
const dbFactory = require("./use-template-db")
|
||||||
const { ContainerRegistrationKeys } = require("@medusajs/utils")
|
const { ContainerRegistrationKeys } = require("@medusajs/utils")
|
||||||
const { migrateMedusaApp } = require("@medusajs/medusa/dist/loaders/medusa-app")
|
const {
|
||||||
|
runMedusaAppMigrations,
|
||||||
|
} = require("@medusajs/medusa/dist/loaders/medusa-app")
|
||||||
|
|
||||||
const DB_HOST = process.env.DB_HOST
|
const DB_HOST = process.env.DB_HOST
|
||||||
const DB_USERNAME = process.env.DB_USERNAME
|
const DB_USERNAME = process.env.DB_USERNAME
|
||||||
@@ -181,10 +183,7 @@ module.exports = {
|
|||||||
|
|
||||||
instance.setPgConnection(pgConnection)
|
instance.setPgConnection(pgConnection)
|
||||||
|
|
||||||
await migrateMedusaApp(
|
await runMedusaAppMigrations({ configModule, container })
|
||||||
{ configModule, container },
|
|
||||||
{ registerInContainer: false }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dbDataSource
|
return dbDataSource
|
||||||
|
|||||||
@@ -176,10 +176,10 @@ function buildLocalCommands(cli, isLocalProject) {
|
|||||||
action: {
|
action: {
|
||||||
demand: true,
|
demand: true,
|
||||||
description: "The action to perform on migrations",
|
description: "The action to perform on migrations",
|
||||||
choices: ["run", "revert", "show"],
|
choices: ["run", "revert", "show", "generate"],
|
||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
description: "Revert migrations for defined modules",
|
description: "Modules for which to run the action (revert, generate)",
|
||||||
demand: false,
|
demand: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -39,9 +39,9 @@ export async function initDb({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
migrateMedusaApp,
|
runMedusaAppMigrations,
|
||||||
} = require("@medusajs/medusa/dist/loaders/medusa-app")
|
} = require("@medusajs/medusa/dist/loaders/medusa-app")
|
||||||
await migrateMedusaApp({ configModule, container })
|
await runMedusaAppMigrations({ configModule, container })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Something went wrong while running the migrations")
|
console.error("Something went wrong while running the migrations")
|
||||||
throw err
|
throw err
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
Constructor,
|
Constructor,
|
||||||
IModuleService,
|
IModuleService,
|
||||||
InternalModuleDeclaration,
|
InternalModuleDeclaration,
|
||||||
|
LoaderOptions,
|
||||||
Logger,
|
Logger,
|
||||||
MedusaContainer,
|
MedusaContainer,
|
||||||
ModuleExports,
|
ModuleExports,
|
||||||
@@ -32,6 +33,11 @@ type ModuleResource = {
|
|||||||
normalizedPath: string
|
normalizedPath: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MigrationFunction = (
|
||||||
|
options: LoaderOptions<any>,
|
||||||
|
moduleDeclaration?: InternalModuleDeclaration
|
||||||
|
) => Promise<void>
|
||||||
|
|
||||||
export async function loadInternalModule(
|
export async function loadInternalModule(
|
||||||
container: MedusaContainer,
|
container: MedusaContainer,
|
||||||
resolution: ModuleResolution,
|
resolution: ModuleResolution,
|
||||||
@@ -171,7 +177,11 @@ export async function loadInternalModule(
|
|||||||
export async function loadModuleMigrations(
|
export async function loadModuleMigrations(
|
||||||
resolution: ModuleResolution,
|
resolution: ModuleResolution,
|
||||||
moduleExports?: ModuleExports
|
moduleExports?: ModuleExports
|
||||||
): Promise<[Function | undefined, Function | undefined]> {
|
): Promise<{
|
||||||
|
runMigrations?: MigrationFunction
|
||||||
|
revertMigration?: MigrationFunction
|
||||||
|
generateMigration?: MigrationFunction
|
||||||
|
}> {
|
||||||
let loadedModule: ModuleExports
|
let loadedModule: ModuleExports
|
||||||
try {
|
try {
|
||||||
loadedModule =
|
loadedModule =
|
||||||
@@ -179,6 +189,7 @@ export async function loadModuleMigrations(
|
|||||||
|
|
||||||
let runMigrations = loadedModule.runMigrations
|
let runMigrations = loadedModule.runMigrations
|
||||||
let revertMigration = loadedModule.revertMigration
|
let revertMigration = loadedModule.revertMigration
|
||||||
|
let generateMigration = loadedModule.generateMigration
|
||||||
|
|
||||||
if (!runMigrations || !revertMigration) {
|
if (!runMigrations || !revertMigration) {
|
||||||
const moduleResources = await loadResources(
|
const moduleResources = await loadResources(
|
||||||
@@ -189,6 +200,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: join(moduleResources.normalizedPath, "migrations"),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,11 +211,15 @@ export async function loadModuleMigrations(
|
|||||||
revertMigration ??= ModulesSdkUtils.buildRevertMigrationScript(
|
revertMigration ??= ModulesSdkUtils.buildRevertMigrationScript(
|
||||||
migrationScriptOptions
|
migrationScriptOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
|
generateMigration ??= ModulesSdkUtils.buildGenerateMigrationScript(
|
||||||
|
migrationScriptOptions
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return [runMigrations, revertMigration]
|
return { runMigrations, revertMigration, generateMigration }
|
||||||
} catch {
|
} catch {
|
||||||
return [undefined, undefined]
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,11 @@ import {
|
|||||||
import { asValue } from "awilix"
|
import { asValue } from "awilix"
|
||||||
import type { Knex } from "knex"
|
import type { Knex } from "knex"
|
||||||
import { MODULE_PACKAGE_NAMES } from "./definitions"
|
import { MODULE_PACKAGE_NAMES } from "./definitions"
|
||||||
import { MedusaModule, RegisterModuleJoinerConfig } from "./medusa-module"
|
import {
|
||||||
|
MedusaModule,
|
||||||
|
MigrationOptions,
|
||||||
|
RegisterModuleJoinerConfig,
|
||||||
|
} from "./medusa-module"
|
||||||
import { RemoteLink } from "./remote-link"
|
import { RemoteLink } from "./remote-link"
|
||||||
import { RemoteQuery } from "./remote-query"
|
import { RemoteQuery } from "./remote-query"
|
||||||
import { MODULE_RESOURCE_TYPE, MODULE_SCOPE } from "./types"
|
import { MODULE_RESOURCE_TYPE, MODULE_SCOPE } from "./types"
|
||||||
@@ -51,6 +55,7 @@ declare module "@medusajs/types" {
|
|||||||
|
|
||||||
export type RunMigrationFn = () => Promise<void>
|
export type RunMigrationFn = () => Promise<void>
|
||||||
export type RevertMigrationFn = (moduleNames: string[]) => Promise<void>
|
export type RevertMigrationFn = (moduleNames: string[]) => Promise<void>
|
||||||
|
export type GenerateMigrations = (moduleNames: string[]) => Promise<void>
|
||||||
|
|
||||||
export type MedusaModuleConfig = {
|
export type MedusaModuleConfig = {
|
||||||
[key: string | Modules]:
|
[key: string | Modules]:
|
||||||
@@ -225,6 +230,7 @@ export type MedusaAppOutput = {
|
|||||||
notFound?: Record<string, Record<string, string>>
|
notFound?: Record<string, Record<string, string>>
|
||||||
runMigrations: RunMigrationFn
|
runMigrations: RunMigrationFn
|
||||||
revertMigrations: RevertMigrationFn
|
revertMigrations: RevertMigrationFn
|
||||||
|
generateMigrations: GenerateMigrations
|
||||||
onApplicationShutdown: () => Promise<void>
|
onApplicationShutdown: () => Promise<void>
|
||||||
onApplicationPrepareShutdown: () => Promise<void>
|
onApplicationPrepareShutdown: () => Promise<void>
|
||||||
sharedContainer?: MedusaContainer
|
sharedContainer?: MedusaContainer
|
||||||
@@ -354,6 +360,9 @@ async function MedusaApp_({
|
|||||||
revertMigrations: async () => {
|
revertMigrations: async () => {
|
||||||
throw new Error("Revert migrations not allowed in loaderOnly mode")
|
throw new Error("Revert migrations not allowed in loaderOnly mode")
|
||||||
},
|
},
|
||||||
|
generateMigrations: async () => {
|
||||||
|
throw new Error("Generate migrations not allowed in loaderOnly mode")
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,10 +415,10 @@ async function MedusaApp_({
|
|||||||
|
|
||||||
const applyMigration = async ({
|
const applyMigration = async ({
|
||||||
modulesNames,
|
modulesNames,
|
||||||
revert = false,
|
action = "run",
|
||||||
}: {
|
}: {
|
||||||
modulesNames: string[]
|
modulesNames: string[]
|
||||||
revert?: boolean
|
action?: "run" | "revert" | "generate"
|
||||||
}) => {
|
}) => {
|
||||||
const moduleResolutions = modulesNames.map((moduleName) => {
|
const moduleResolutions = modulesNames.map((moduleName) => {
|
||||||
return {
|
return {
|
||||||
@@ -423,7 +432,6 @@ async function MedusaApp_({
|
|||||||
.map(({ moduleName }) => moduleName)
|
.map(({ moduleName }) => moduleName)
|
||||||
|
|
||||||
if (missingModules.length) {
|
if (missingModules.length) {
|
||||||
const action = revert ? "revert" : "run"
|
|
||||||
const error = new MedusaError(
|
const error = new MedusaError(
|
||||||
MedusaError.Types.UNKNOWN_MODULES,
|
MedusaError.Types.UNKNOWN_MODULES,
|
||||||
`Cannot ${action} migrations for unknown module(s) ${missingModules.join(
|
`Cannot ${action} migrations for unknown module(s) ${missingModules.join(
|
||||||
@@ -443,22 +451,20 @@ async function MedusaApp_({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (revert) {
|
const migrationOptions: MigrationOptions = {
|
||||||
await MedusaModule.migrateDown(
|
moduleKey: moduleResolution.definition.key,
|
||||||
moduleResolution.definition.key,
|
modulePath: moduleResolution.resolutionPath as string,
|
||||||
moduleResolution.resolutionPath as string,
|
container: sharedContainer,
|
||||||
sharedContainer,
|
options: moduleResolution.options,
|
||||||
moduleResolution.options,
|
moduleExports: moduleResolution.moduleExports,
|
||||||
moduleResolution.moduleExports
|
}
|
||||||
)
|
|
||||||
|
if (action === "revert") {
|
||||||
|
await MedusaModule.migrateDown(migrationOptions)
|
||||||
|
} else if (action === "run") {
|
||||||
|
await MedusaModule.migrateUp(migrationOptions)
|
||||||
} else {
|
} else {
|
||||||
await MedusaModule.migrateUp(
|
await MedusaModule.migrateGenerate(migrationOptions)
|
||||||
moduleResolution.definition.key,
|
|
||||||
moduleResolution.resolutionPath as string,
|
|
||||||
sharedContainer,
|
|
||||||
moduleResolution.options,
|
|
||||||
moduleResolution.moduleExports
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -493,7 +499,7 @@ async function MedusaApp_({
|
|||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
await applyMigration({
|
await applyMigration({
|
||||||
modulesNames,
|
modulesNames,
|
||||||
revert: true,
|
action: "revert",
|
||||||
})
|
})
|
||||||
|
|
||||||
const options: Partial<ModuleServiceInitializeOptions> =
|
const options: Partial<ModuleServiceInitializeOptions> =
|
||||||
@@ -516,6 +522,15 @@ async function MedusaApp_({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const generateMigrations: GenerateMigrations = async (
|
||||||
|
modulesNames
|
||||||
|
): Promise<void> => {
|
||||||
|
await applyMigration({
|
||||||
|
modulesNames,
|
||||||
|
action: "generate",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onApplicationShutdown,
|
onApplicationShutdown,
|
||||||
onApplicationPrepareShutdown,
|
onApplicationPrepareShutdown,
|
||||||
@@ -526,6 +541,7 @@ async function MedusaApp_({
|
|||||||
notFound,
|
notFound,
|
||||||
runMigrations,
|
runMigrations,
|
||||||
revertMigrations,
|
revertMigrations,
|
||||||
|
generateMigrations,
|
||||||
sharedContainer: sharedContainer_,
|
sharedContainer: sharedContainer_,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -566,3 +582,17 @@ export async function MedusaAppMigrateDown(
|
|||||||
|
|
||||||
await revertMigrations(moduleNames).finally(MedusaModule.clearInstances)
|
await revertMigrations(moduleNames).finally(MedusaModule.clearInstances)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function MedusaAppMigrateGenerate(
|
||||||
|
moduleNames: string[],
|
||||||
|
options: MedusaAppOptions = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const migrationOnly = true
|
||||||
|
|
||||||
|
const { generateMigrations } = await MedusaApp_({
|
||||||
|
...options,
|
||||||
|
migrationOnly,
|
||||||
|
})
|
||||||
|
|
||||||
|
await generateMigrations(moduleNames).finally(MedusaModule.clearInstances)
|
||||||
|
}
|
||||||
@@ -52,6 +52,14 @@ type ModuleAlias = {
|
|||||||
main?: boolean
|
main?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MigrationOptions = {
|
||||||
|
moduleKey: string
|
||||||
|
modulePath: string
|
||||||
|
container?: MedusaContainer
|
||||||
|
options?: Record<string, any>
|
||||||
|
moduleExports?: ModuleExports
|
||||||
|
}
|
||||||
|
|
||||||
export type ModuleBootstrapOptions = {
|
export type ModuleBootstrapOptions = {
|
||||||
moduleKey: string
|
moduleKey: string
|
||||||
defaultPath: string
|
defaultPath: string
|
||||||
@@ -536,13 +544,13 @@ class MedusaModule {
|
|||||||
return services
|
return services
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async migrateUp(
|
public static async migrateGenerate({
|
||||||
moduleKey: string,
|
options,
|
||||||
modulePath: string,
|
container,
|
||||||
container?: MedusaContainer,
|
moduleExports,
|
||||||
options?: Record<string, any>,
|
moduleKey,
|
||||||
moduleExports?: ModuleExports
|
modulePath,
|
||||||
): Promise<void> {
|
}: MigrationOptions): Promise<void> {
|
||||||
const moduleResolutions = registerMedusaModule(moduleKey, {
|
const moduleResolutions = registerMedusaModule(moduleKey, {
|
||||||
scope: MODULE_SCOPE.INTERNAL,
|
scope: MODULE_SCOPE.INTERNAL,
|
||||||
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
||||||
@@ -555,28 +563,31 @@ class MedusaModule {
|
|||||||
allowUnregistered: true,
|
allowUnregistered: true,
|
||||||
}) ?? logger
|
}) ?? logger
|
||||||
|
|
||||||
|
container ??= createMedusaContainer()
|
||||||
|
|
||||||
for (const mod in moduleResolutions) {
|
for (const mod in moduleResolutions) {
|
||||||
const [migrateUp] = await loadModuleMigrations(
|
const { generateMigration } = await loadModuleMigrations(
|
||||||
moduleResolutions[mod],
|
moduleResolutions[mod],
|
||||||
moduleExports
|
moduleExports
|
||||||
)
|
)
|
||||||
|
|
||||||
if (typeof migrateUp === "function") {
|
if (typeof generateMigration === "function") {
|
||||||
await migrateUp({
|
await generateMigration({
|
||||||
options,
|
options,
|
||||||
|
container: container!,
|
||||||
logger: logger_,
|
logger: logger_,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async migrateDown(
|
public static async migrateUp({
|
||||||
moduleKey: string,
|
options,
|
||||||
modulePath: string,
|
container,
|
||||||
container?: MedusaContainer,
|
moduleExports,
|
||||||
options?: Record<string, any>,
|
moduleKey,
|
||||||
moduleExports?: ModuleExports
|
modulePath,
|
||||||
): Promise<void> {
|
}: MigrationOptions): Promise<void> {
|
||||||
const moduleResolutions = registerMedusaModule(moduleKey, {
|
const moduleResolutions = registerMedusaModule(moduleKey, {
|
||||||
scope: MODULE_SCOPE.INTERNAL,
|
scope: MODULE_SCOPE.INTERNAL,
|
||||||
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
||||||
@@ -589,15 +600,55 @@ class MedusaModule {
|
|||||||
allowUnregistered: true,
|
allowUnregistered: true,
|
||||||
}) ?? logger
|
}) ?? logger
|
||||||
|
|
||||||
|
container ??= createMedusaContainer()
|
||||||
|
|
||||||
for (const mod in moduleResolutions) {
|
for (const mod in moduleResolutions) {
|
||||||
const [, migrateDown] = await loadModuleMigrations(
|
const { runMigrations } = await loadModuleMigrations(
|
||||||
moduleResolutions[mod],
|
moduleResolutions[mod],
|
||||||
moduleExports
|
moduleExports
|
||||||
)
|
)
|
||||||
|
|
||||||
if (typeof migrateDown === "function") {
|
if (typeof runMigrations === "function") {
|
||||||
await migrateDown({
|
await runMigrations({
|
||||||
options,
|
options,
|
||||||
|
container: container!,
|
||||||
|
logger: logger_,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async migrateDown({
|
||||||
|
options,
|
||||||
|
container,
|
||||||
|
moduleExports,
|
||||||
|
moduleKey,
|
||||||
|
modulePath,
|
||||||
|
}: MigrationOptions): Promise<void> {
|
||||||
|
const moduleResolutions = registerMedusaModule(moduleKey, {
|
||||||
|
scope: MODULE_SCOPE.INTERNAL,
|
||||||
|
resources: MODULE_RESOURCE_TYPE.ISOLATED,
|
||||||
|
resolve: modulePath,
|
||||||
|
options,
|
||||||
|
})
|
||||||
|
|
||||||
|
const logger_ =
|
||||||
|
container?.resolve(ContainerRegistrationKeys.LOGGER, {
|
||||||
|
allowUnregistered: true,
|
||||||
|
}) ?? logger
|
||||||
|
|
||||||
|
container ??= createMedusaContainer()
|
||||||
|
|
||||||
|
for (const mod in moduleResolutions) {
|
||||||
|
const { revertMigration } = await loadModuleMigrations(
|
||||||
|
moduleResolutions[mod],
|
||||||
|
moduleExports
|
||||||
|
)
|
||||||
|
|
||||||
|
if (typeof revertMigration === "function") {
|
||||||
|
await revertMigration({
|
||||||
|
options,
|
||||||
|
container: container!,
|
||||||
logger: logger_,
|
logger: logger_,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,6 +235,10 @@ export type ModuleExports<T = Constructor<any>> = {
|
|||||||
options: LoaderOptions<any>,
|
options: LoaderOptions<any>,
|
||||||
moduleDeclaration?: InternalModuleDeclaration
|
moduleDeclaration?: InternalModuleDeclaration
|
||||||
): Promise<void>
|
): Promise<void>
|
||||||
|
generateMigration?(
|
||||||
|
options: LoaderOptions<any>,
|
||||||
|
moduleDeclaration?: InternalModuleDeclaration
|
||||||
|
): Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModuleServiceInitializeOptions {
|
export interface ModuleServiceInitializeOptions {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import {
|
|||||||
} 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"
|
import { PostgreSqlDriver } from "@mikro-orm/postgresql"
|
||||||
|
import { dirname } from "path"
|
||||||
|
import { access, mkdir, writeFile } from "fs/promises"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Events emitted by the migrations class
|
* Events emitted by the migrations class
|
||||||
@@ -56,7 +58,9 @@ export class Migrations extends EventEmitter<MigrationsEvents> {
|
|||||||
async generate(): Promise<MigrationResult> {
|
async generate(): Promise<MigrationResult> {
|
||||||
const connection = await this.#getConnection()
|
const connection = await this.#getConnection()
|
||||||
const migrator = connection.getMigrator()
|
const migrator = connection.getMigrator()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
await this.ensureSnapshot(migrator["snapshotPath"])
|
||||||
return await migrator.createMigration()
|
return await migrator.createMigration()
|
||||||
} finally {
|
} finally {
|
||||||
await connection.close(true)
|
await connection.close(true)
|
||||||
@@ -134,4 +138,35 @@ export class Migrations extends EventEmitter<MigrationsEvents> {
|
|||||||
await connection.close(true)
|
await connection.close(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a default snapshot file if it does not already exists. This
|
||||||
|
* prevent from creating a database to manage the migrations and instead
|
||||||
|
* rely on the snapshot.
|
||||||
|
*
|
||||||
|
* @param snapshotPath
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected async ensureSnapshot(snapshotPath: string): Promise<void> {
|
||||||
|
await mkdir(dirname(snapshotPath), { recursive: true })
|
||||||
|
|
||||||
|
const doesFileExists = await access(snapshotPath)
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false)
|
||||||
|
|
||||||
|
if (doesFileExists) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptySnapshotContent = JSON.stringify(
|
||||||
|
{
|
||||||
|
tables: [],
|
||||||
|
namespaces: [],
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
|
||||||
|
await writeFile(snapshotPath, emptySnapshotContent, "utf-8")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
-12
@@ -1,7 +1,6 @@
|
|||||||
import { join } from "path"
|
import { join } from "path"
|
||||||
import { setTimeout } from "timers/promises"
|
import { setTimeout } from "timers/promises"
|
||||||
import { MetadataStorage } from "@mikro-orm/core"
|
import { MetadataStorage } from "@mikro-orm/core"
|
||||||
import { createDatabase, dropDatabase } from "pg-god"
|
|
||||||
|
|
||||||
import { Migrations } from "../../index"
|
import { Migrations } from "../../index"
|
||||||
import { FileSystem } from "../../../common"
|
import { FileSystem } from "../../../common"
|
||||||
@@ -22,22 +21,12 @@ const pgGodCredentials = {
|
|||||||
host: DB_HOST,
|
host: DB_HOST,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Reenable once flakiness is taken care of
|
describe("Generate migrations", () => {
|
||||||
describe.skip("Generate migrations", () => {
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await dropDatabase(
|
|
||||||
{ databaseName: dbName, errorIfNonExist: false },
|
|
||||||
pgGodCredentials
|
|
||||||
)
|
|
||||||
await fs.cleanup()
|
await fs.cleanup()
|
||||||
await createDatabase({ databaseName: dbName }, pgGodCredentials)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
await dropDatabase(
|
|
||||||
{ databaseName: dbName, errorIfNonExist: false },
|
|
||||||
pgGodCredentials
|
|
||||||
)
|
|
||||||
await fs.cleanup()
|
await fs.cleanup()
|
||||||
MetadataStorage.clear()
|
MetadataStorage.clear()
|
||||||
}, 300 * 1000)
|
}, 300 * 1000)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from "./migration-down"
|
export * from "./migration-down"
|
||||||
export * from "./migration-up"
|
export * from "./migration-up"
|
||||||
|
export * from "./migration-generate"
|
||||||
export * from "./seed"
|
export * from "./seed"
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { LoaderOptions, Logger, ModulesSdkTypes } from "@medusajs/types"
|
||||||
|
import { mikroOrmCreateConnection } from "../../dal"
|
||||||
|
import { loadDatabaseConfig } from "../load-module-database-config"
|
||||||
|
import { Migrations } from "../../migrations"
|
||||||
|
import { toMikroOrmEntities } from "../../dml"
|
||||||
|
|
||||||
|
const TERMINAL_SIZE = process.stdout.columns
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to build a migration generation script that will generate the migrations.
|
||||||
|
* Only used in mikro orm based modules.
|
||||||
|
* @param moduleName
|
||||||
|
* @param models
|
||||||
|
* @param pathToMigrations
|
||||||
|
*/
|
||||||
|
export function buildGenerateMigrationScript({
|
||||||
|
moduleName,
|
||||||
|
models,
|
||||||
|
pathToMigrations,
|
||||||
|
}) {
|
||||||
|
/**
|
||||||
|
* This script is only valid for mikro orm managers. If a user provide a custom manager
|
||||||
|
* he is in charge of running the migrations.
|
||||||
|
* @param options
|
||||||
|
* @param logger
|
||||||
|
* @param moduleDeclaration
|
||||||
|
*/
|
||||||
|
return async function ({
|
||||||
|
options,
|
||||||
|
logger,
|
||||||
|
}: Pick<
|
||||||
|
LoaderOptions<ModulesSdkTypes.ModuleServiceInitializeOptions>,
|
||||||
|
"options" | "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 normalizedModels = toMikroOrmEntities(models)
|
||||||
|
const orm = await mikroOrmCreateConnection(
|
||||||
|
dbData,
|
||||||
|
normalizedModels,
|
||||||
|
pathToMigrations
|
||||||
|
)
|
||||||
|
|
||||||
|
const migrations = new Migrations(orm)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { fileName } = await migrations.generate()
|
||||||
|
if (fileName) {
|
||||||
|
logger.info(`Generated successfully (${fileName}).`)
|
||||||
|
} else {
|
||||||
|
logger.info(`Skipped. No changes detected in your models.`)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`Failed with error ${error.message}`, error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import Logger from "../loaders/logger"
|
import Logger from "../loaders/logger"
|
||||||
import { migrateMedusaApp, revertMedusaApp } from "../loaders/medusa-app"
|
import { runMedusaAppMigrations } from "../loaders/medusa-app"
|
||||||
import { initializeContainer } from "../loaders"
|
import { initializeContainer } from "../loaders"
|
||||||
import { ContainerRegistrationKeys, MedusaError } from "@medusajs/utils"
|
import { ContainerRegistrationKeys, MedusaError } from "@medusajs/utils"
|
||||||
import { getResolvedPlugins } from "../loaders/helpers/resolve-plugins"
|
import { getResolvedPlugins } from "../loaders/helpers/resolve-plugins"
|
||||||
@@ -7,13 +7,44 @@ import { resolvePluginsLinks } from "../loaders/helpers/resolve-plugins-links"
|
|||||||
|
|
||||||
const TERMINAL_SIZE = process.stdout.columns
|
const TERMINAL_SIZE = process.stdout.columns
|
||||||
|
|
||||||
|
type Action = "run" | "revert" | "generate" | "show"
|
||||||
|
|
||||||
|
function validateInputArgs({
|
||||||
|
action,
|
||||||
|
modules,
|
||||||
|
}: {
|
||||||
|
action: Action
|
||||||
|
modules: string[]
|
||||||
|
}) {
|
||||||
|
const actionsRequiringModules = ["revert", "generate"]
|
||||||
|
|
||||||
|
if (modules.length && !actionsRequiringModules.includes(action)) {
|
||||||
|
Logger.error(
|
||||||
|
`<modules> cannot be specified with the "${action}" action. Please remove the <modules> argument and try again.`
|
||||||
|
)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!modules.length && actionsRequiringModules.includes(action)) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 action = args[0] as "run" | "revert" | "generate" | "show"
|
||||||
|
const modules = args.splice(1)
|
||||||
|
|
||||||
|
validateInputArgs({ action, modules })
|
||||||
|
|
||||||
const container = await initializeContainer(directory)
|
const container = await initializeContainer(directory)
|
||||||
|
|
||||||
const configModule = container.resolve(
|
const configModule = container.resolve(
|
||||||
@@ -26,33 +57,26 @@ const main = async function ({ directory }) {
|
|||||||
if (action === "run") {
|
if (action === "run") {
|
||||||
Logger.info("Running migrations...")
|
Logger.info("Running migrations...")
|
||||||
|
|
||||||
await migrateMedusaApp({
|
await runMedusaAppMigrations({
|
||||||
configModule,
|
configModule,
|
||||||
linkModules: pluginLinks,
|
linkModules: pluginLinks,
|
||||||
container,
|
container,
|
||||||
|
action: "run",
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(new Array(TERMINAL_SIZE).join("-"))
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
Logger.info("Migrations completed")
|
Logger.info("Migrations completed")
|
||||||
process.exit()
|
process.exit()
|
||||||
} else if (action === "revert") {
|
} else if (action === "revert") {
|
||||||
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("Reverting migrations...")
|
Logger.info("Reverting migrations...")
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await revertMedusaApp({
|
await runMedusaAppMigrations({
|
||||||
modulesToRevert,
|
moduleNames: modules,
|
||||||
configModule,
|
configModule,
|
||||||
linkModules: pluginLinks,
|
linkModules: pluginLinks,
|
||||||
container,
|
container,
|
||||||
|
action: "revert",
|
||||||
})
|
})
|
||||||
console.log(new Array(TERMINAL_SIZE).join("-"))
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
Logger.info("Migrations reverted")
|
Logger.info("Migrations reverted")
|
||||||
@@ -70,6 +94,20 @@ const main = async function ({ directory }) {
|
|||||||
}
|
}
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
} else if (action === "generate") {
|
||||||
|
Logger.info("Generating migrations...")
|
||||||
|
|
||||||
|
await runMedusaAppMigrations({
|
||||||
|
moduleNames: modules,
|
||||||
|
configModule,
|
||||||
|
linkModules: pluginLinks,
|
||||||
|
container,
|
||||||
|
action: "generate",
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
|
Logger.info("Migrations generated")
|
||||||
|
process.exit()
|
||||||
} else if (action === "show") {
|
} else if (action === "show") {
|
||||||
Logger.info("Action not supported yet")
|
Logger.info("Action not supported yet")
|
||||||
process.exit(0)
|
process.exit(0)
|
||||||
|
|||||||
@@ -126,11 +126,11 @@ export const runIsolatedModulesMigration = async (configModule) => {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
await MedusaModule.migrateUp(
|
await MedusaModule.migrateUp({
|
||||||
moduleResolution.definition.key,
|
moduleKey: moduleResolution.definition.key,
|
||||||
moduleResolution.resolutionPath,
|
modulePath: moduleResolution.resolutionPath,
|
||||||
moduleResolution.options
|
options: moduleResolution.options,
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,10 +151,10 @@ export const revertIsolatedModulesMigration = async (configModule) => {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
await MedusaModule.migrateDown(
|
await MedusaModule.migrateDown({
|
||||||
moduleResolution.definition.key,
|
moduleKey: moduleResolution.definition.key,
|
||||||
moduleResolution.resolutionPath,
|
modulePath: moduleResolution.resolutionPath,
|
||||||
moduleResolution.options
|
options: moduleResolution.options,
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
MedusaApp,
|
MedusaApp,
|
||||||
MedusaAppMigrateDown,
|
MedusaAppMigrateDown,
|
||||||
|
MedusaAppMigrateGenerate,
|
||||||
MedusaAppMigrateUp,
|
MedusaAppMigrateUp,
|
||||||
MedusaAppOptions,
|
MedusaAppOptions,
|
||||||
MedusaAppOutput,
|
MedusaAppOutput,
|
||||||
@@ -57,12 +58,21 @@ export function mergeDefaultModules(
|
|||||||
return configModules
|
return configModules
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runMedusaAppMigrations({
|
/**
|
||||||
|
* Run, Revert or Generate the migrations for the medusa app.
|
||||||
|
*
|
||||||
|
* @param configModule
|
||||||
|
* @param container
|
||||||
|
* @param moduleNames
|
||||||
|
* @param linkModules
|
||||||
|
* @param action
|
||||||
|
*/
|
||||||
|
export async function runMedusaAppMigrations({
|
||||||
configModule,
|
configModule,
|
||||||
container,
|
container,
|
||||||
moduleNames,
|
moduleNames,
|
||||||
revert = false,
|
|
||||||
linkModules,
|
linkModules,
|
||||||
|
action = "run",
|
||||||
}: {
|
}: {
|
||||||
configModule: {
|
configModule: {
|
||||||
modules?: CommonTypes.ConfigModule["modules"]
|
modules?: CommonTypes.ConfigModule["modules"]
|
||||||
@@ -73,11 +83,11 @@ async function runMedusaAppMigrations({
|
|||||||
} & (
|
} & (
|
||||||
| {
|
| {
|
||||||
moduleNames?: never
|
moduleNames?: never
|
||||||
revert: false
|
action: "run"
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
moduleNames: string[]
|
moduleNames: string[]
|
||||||
revert: true
|
action: "revert" | "generate"
|
||||||
}
|
}
|
||||||
)): Promise<void> {
|
)): Promise<void> {
|
||||||
const injectedDependencies = {
|
const injectedDependencies = {
|
||||||
@@ -101,82 +111,23 @@ async function runMedusaAppMigrations({
|
|||||||
}
|
}
|
||||||
const configModules = mergeDefaultModules(configModule.modules)
|
const configModules = mergeDefaultModules(configModule.modules)
|
||||||
|
|
||||||
if (revert) {
|
const migrationOptions = {
|
||||||
await MedusaAppMigrateDown(moduleNames!, {
|
|
||||||
modulesConfig: configModules,
|
modulesConfig: configModules,
|
||||||
sharedContainer: container,
|
sharedContainer: container,
|
||||||
linkModules,
|
linkModules,
|
||||||
sharedResourcesConfig,
|
sharedResourcesConfig,
|
||||||
injectedDependencies,
|
injectedDependencies,
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if (action === "revert") {
|
||||||
|
await MedusaAppMigrateDown(moduleNames!, migrationOptions)
|
||||||
|
} else if (action === "run") {
|
||||||
|
await MedusaAppMigrateUp(migrationOptions)
|
||||||
} else {
|
} else {
|
||||||
await MedusaAppMigrateUp({
|
await MedusaAppMigrateGenerate(moduleNames!, migrationOptions)
|
||||||
modulesConfig: configModules,
|
|
||||||
sharedContainer: container,
|
|
||||||
linkModules,
|
|
||||||
sharedResourcesConfig,
|
|
||||||
injectedDependencies,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param configModule The config module
|
|
||||||
* @param linkModules Custom links from the plugins
|
|
||||||
* @param container The medusa container
|
|
||||||
*/
|
|
||||||
export async function migrateMedusaApp({
|
|
||||||
configModule,
|
|
||||||
linkModules,
|
|
||||||
container,
|
|
||||||
}: {
|
|
||||||
configModule: {
|
|
||||||
modules?: CommonTypes.ConfigModule["modules"]
|
|
||||||
projectConfig: CommonTypes.ConfigModule["projectConfig"]
|
|
||||||
}
|
|
||||||
container: MedusaContainer
|
|
||||||
linkModules?: MedusaAppOptions["linkModules"]
|
|
||||||
}): Promise<void> {
|
|
||||||
await runMedusaAppMigrations({
|
|
||||||
configModule,
|
|
||||||
container,
|
|
||||||
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({
|
|
||||||
modulesToRevert,
|
|
||||||
configModule,
|
|
||||||
linkModules,
|
|
||||||
container,
|
|
||||||
}: {
|
|
||||||
modulesToRevert: string[]
|
|
||||||
configModule: {
|
|
||||||
modules?: CommonTypes.ConfigModule["modules"]
|
|
||||||
projectConfig: CommonTypes.ConfigModule["projectConfig"]
|
|
||||||
}
|
|
||||||
container: MedusaContainer
|
|
||||||
linkModules?: MedusaAppOptions["linkModules"]
|
|
||||||
}): Promise<void> {
|
|
||||||
await runMedusaAppMigrations({
|
|
||||||
moduleNames: modulesToRevert,
|
|
||||||
configModule,
|
|
||||||
container,
|
|
||||||
revert: true,
|
|
||||||
linkModules,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadMedusaApp = async (
|
export const loadMedusaApp = async (
|
||||||
{
|
{
|
||||||
container,
|
container,
|
||||||
|
|||||||
Reference in new issue
Block a user