chore(): Accept an extra agument 'all-or-nothing' on the migrate command (#14262)
* chore(): Accept an extra agument 'all-or-nothing' on the migrate command * Create rich-camels-brush.md * chore(): Accept an extra agument 'all-or-nothing' on the migrate command * chore(): Accept an extra agument 'all-or-nothing' on the migrate command * chore(): Accept an extra agument 'all-or-nothing' on the migrate command * chore(): fix broken down migrations * chore(): update changeset
This commit is contained in:
@@ -48,6 +48,14 @@ type ModuleResource = {
|
||||
type MigrationFunction = (
|
||||
options: LoaderOptions<any>,
|
||||
moduleDeclaration?: InternalModuleDeclaration
|
||||
) => Promise<{ name: string; path: string }[]>
|
||||
type RevertMigrationFunction = (
|
||||
options: LoaderOptions<any> & { migrationNames?: string[] },
|
||||
moduleDeclaration?: InternalModuleDeclaration
|
||||
) => Promise<void>
|
||||
type GenerateMigrationFunction = (
|
||||
options: LoaderOptions<any>,
|
||||
moduleDeclaration?: InternalModuleDeclaration
|
||||
) => Promise<void>
|
||||
|
||||
type ResolvedModule = ModuleExports & {
|
||||
@@ -390,8 +398,8 @@ export async function loadModuleMigrations(
|
||||
moduleExports?: ModuleExports
|
||||
): Promise<{
|
||||
runMigrations?: MigrationFunction
|
||||
revertMigration?: MigrationFunction
|
||||
generateMigration?: MigrationFunction
|
||||
revertMigration?: RevertMigrationFunction
|
||||
generateMigration?: GenerateMigrationFunction
|
||||
}> {
|
||||
const runMigrationsFn: ((...args) => Promise<any>)[] = []
|
||||
const revertMigrationFn: ((...args) => Promise<any>)[] = []
|
||||
@@ -488,9 +496,12 @@ export async function loadModuleMigrations(
|
||||
}
|
||||
|
||||
const runMigrations = async (...args) => {
|
||||
let result: { name: string; path: string }[] = []
|
||||
for (const migration of runMigrationsFn.filter(Boolean)) {
|
||||
await migration.apply(migration, args)
|
||||
const res = await migration.apply(migration, args)
|
||||
result.push(...res)
|
||||
}
|
||||
return result
|
||||
}
|
||||
const revertMigration = async (...args) => {
|
||||
for (const migration of revertMigrationFn.filter(Boolean)) {
|
||||
|
||||
@@ -47,7 +47,9 @@ import { MODULE_SCOPE } from "./types"
|
||||
|
||||
const LinkModulePackage = MODULE_PACKAGE_NAMES[Modules.LINK]
|
||||
|
||||
export type RunMigrationFn = () => Promise<void>
|
||||
export type RunMigrationFn = (options?: {
|
||||
allOrNothing?: boolean
|
||||
}) => Promise<void>
|
||||
export type RevertMigrationFn = (moduleNames: string[]) => Promise<void>
|
||||
export type GenerateMigrations = (moduleNames: string[]) => Promise<void>
|
||||
export type GetLinkExecutionPlanner = () => ILinkMigrationsPlanner
|
||||
@@ -498,10 +500,12 @@ async function MedusaApp_({
|
||||
const applyMigration = async ({
|
||||
modulesNames,
|
||||
action = "run",
|
||||
allOrNothing = false,
|
||||
}: {
|
||||
modulesNames: string[]
|
||||
action?: "run" | "revert" | "generate"
|
||||
}) => {
|
||||
allOrNothing?: boolean
|
||||
}): Promise<{ name: string; path: string }[] | void> => {
|
||||
const moduleResolutions = Array.from(new Set(modulesNames)).map(
|
||||
(moduleName) => {
|
||||
return {
|
||||
@@ -527,7 +531,11 @@ async function MedusaApp_({
|
||||
throw error
|
||||
}
|
||||
|
||||
const run = async ({ resolution: moduleResolution }) => {
|
||||
let executedResolutions: [any, string[]][] = [] // [moduleResolution, migration names[]]
|
||||
const run = async (
|
||||
{ resolution: moduleResolution },
|
||||
migrationNames?: string[]
|
||||
) => {
|
||||
if (
|
||||
!moduleResolution.options?.database &&
|
||||
moduleResolution.moduleDeclaration?.scope === MODULE_SCOPE.INTERNAL
|
||||
@@ -550,24 +558,62 @@ async function MedusaApp_({
|
||||
}
|
||||
|
||||
if (action === "revert") {
|
||||
await MedusaModule.migrateDown(migrationOptions)
|
||||
await MedusaModule.migrateDown(migrationOptions, migrationNames)
|
||||
} else if (action === "run") {
|
||||
await MedusaModule.migrateUp(migrationOptions)
|
||||
const ranMigrationsResult = await MedusaModule.migrateUp(
|
||||
migrationOptions
|
||||
)
|
||||
|
||||
// Store for revert if anything goes wrong later
|
||||
executedResolutions.push([
|
||||
moduleResolution,
|
||||
ranMigrationsResult?.map((r) => r.name) ?? [],
|
||||
])
|
||||
} else {
|
||||
await MedusaModule.migrateGenerate(migrationOptions)
|
||||
}
|
||||
}
|
||||
|
||||
const concurrency = parseInt(process.env.DB_MIGRATION_CONCURRENCY ?? "1")
|
||||
await executeWithConcurrency(
|
||||
moduleResolutions.map((a) => () => run(a)),
|
||||
concurrency
|
||||
)
|
||||
try {
|
||||
const results = await executeWithConcurrency(
|
||||
moduleResolutions.map((a) => () => run(a)),
|
||||
concurrency
|
||||
)
|
||||
const rejections = results.filter(
|
||||
(result) => result.status === "rejected"
|
||||
)
|
||||
if (rejections.length) {
|
||||
throw new Error(
|
||||
`Some migrations failed to ${action}: ${rejections
|
||||
.map((r) => r.reason)
|
||||
.join(", ")}`
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
if (allOrNothing) {
|
||||
action = "revert"
|
||||
await executeWithConcurrency(
|
||||
executedResolutions.map(
|
||||
([resolution, migrationNames]) =>
|
||||
() =>
|
||||
run({ resolution }, migrationNames)
|
||||
),
|
||||
concurrency
|
||||
)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const runMigrations: RunMigrationFn = async (): Promise<void> => {
|
||||
const runMigrations: RunMigrationFn = async (
|
||||
{ allOrNothing = false }: { allOrNothing?: boolean } = {
|
||||
allOrNothing: false,
|
||||
}
|
||||
): Promise<void> => {
|
||||
await applyMigration({
|
||||
modulesNames: Object.keys(allModules),
|
||||
allOrNothing,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -638,7 +684,7 @@ export async function MedusaApp(
|
||||
}
|
||||
|
||||
export async function MedusaAppMigrateUp(
|
||||
options: MedusaAppOptions = {}
|
||||
options: MedusaAppOptions & { allOrNothing?: boolean } = {}
|
||||
): Promise<void> {
|
||||
const migrationOnly = true
|
||||
|
||||
@@ -647,7 +693,9 @@ export async function MedusaAppMigrateUp(
|
||||
migrationOnly,
|
||||
})
|
||||
|
||||
await runMigrations().finally(MedusaModule.clearInstances)
|
||||
await runMigrations({ allOrNothing: options.allOrNothing }).finally(
|
||||
MedusaModule.clearInstances
|
||||
)
|
||||
}
|
||||
|
||||
export async function MedusaAppMigrateDown(
|
||||
|
||||
@@ -828,7 +828,7 @@ class MedusaModule {
|
||||
moduleKey,
|
||||
modulePath,
|
||||
cwd,
|
||||
}: MigrationOptions): Promise<void> {
|
||||
}: MigrationOptions): Promise<{ name: string; path: string }[]> {
|
||||
const moduleResolutions = registerMedusaModule({
|
||||
moduleKey,
|
||||
moduleDeclaration: {
|
||||
@@ -846,6 +846,7 @@ class MedusaModule {
|
||||
|
||||
container ??= createMedusaContainer()
|
||||
|
||||
let result: { name: string; path: string }[] = []
|
||||
for (const mod in moduleResolutions) {
|
||||
const { runMigrations } = await loadModuleMigrations(
|
||||
container,
|
||||
@@ -854,23 +855,29 @@ class MedusaModule {
|
||||
)
|
||||
|
||||
if (typeof runMigrations === "function") {
|
||||
await runMigrations({
|
||||
const res = await runMigrations({
|
||||
options,
|
||||
container: container!,
|
||||
logger: logger_,
|
||||
})
|
||||
result.push(...res)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
public static async migrateDown({
|
||||
options,
|
||||
container,
|
||||
moduleExports,
|
||||
moduleKey,
|
||||
modulePath,
|
||||
cwd,
|
||||
}: MigrationOptions): Promise<void> {
|
||||
public static async migrateDown(
|
||||
{
|
||||
options,
|
||||
container,
|
||||
moduleExports,
|
||||
moduleKey,
|
||||
modulePath,
|
||||
cwd,
|
||||
}: MigrationOptions,
|
||||
migrationNames?: string[]
|
||||
): Promise<void> {
|
||||
const moduleResolutions = registerMedusaModule({
|
||||
moduleKey,
|
||||
moduleDeclaration: {
|
||||
@@ -900,6 +907,7 @@ class MedusaModule {
|
||||
options,
|
||||
container: container!,
|
||||
logger: logger_,
|
||||
migrationNames,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user