feat: move migrations commands to the new db namespace (#8810)
This commit is contained in:
@@ -142,6 +142,64 @@ function buildLocalCommands(cli, isLocalProject) {
|
|||||||
})
|
})
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
.command({
|
||||||
|
command: "db:migrate",
|
||||||
|
desc: "Migrate the database by executing pending migrations",
|
||||||
|
builder: (builder) => {
|
||||||
|
builder.option("skip-links", {
|
||||||
|
type: "boolean",
|
||||||
|
describe: "Do not sync links",
|
||||||
|
})
|
||||||
|
builder.option("execute-all-links", {
|
||||||
|
type: "boolean",
|
||||||
|
describe:
|
||||||
|
"Skip prompts and execute all (including unsafe) actions from sync links",
|
||||||
|
})
|
||||||
|
builder.option("execute-safe-links", {
|
||||||
|
type: "boolean",
|
||||||
|
describe:
|
||||||
|
"Skip prompts and execute only safe actions from sync links",
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handler: handlerP(
|
||||||
|
getCommandHandler("db/migrate", (args, cmd) => {
|
||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || `development`
|
||||||
|
return cmd(args)
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.command({
|
||||||
|
command: "db:rollback [modules...]",
|
||||||
|
desc: "Rollback last batch of executed migrations for a given module",
|
||||||
|
builder: {
|
||||||
|
modules: {
|
||||||
|
description: "Modules for which to rollback migrations",
|
||||||
|
demand: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
handler: handlerP(
|
||||||
|
getCommandHandler("db/rollback", (args, cmd) => {
|
||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || `development`
|
||||||
|
return cmd(args)
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.command({
|
||||||
|
command: "db:generate [modules...]",
|
||||||
|
desc: "Generate migrations for a given module",
|
||||||
|
builder: {
|
||||||
|
modules: {
|
||||||
|
description: "Modules for which to generate migration files",
|
||||||
|
demand: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
handler: handlerP(
|
||||||
|
getCommandHandler("db/generate", (args, cmd) => {
|
||||||
|
process.env.NODE_ENV = process.env.NODE_ENV || `development`
|
||||||
|
return cmd(args)
|
||||||
|
})
|
||||||
|
),
|
||||||
|
})
|
||||||
.command({
|
.command({
|
||||||
command: "db:sync-links",
|
command: "db:sync-links",
|
||||||
desc: "Sync database schema with the links defined by your application and Medusa core",
|
desc: "Sync database schema with the links defined by your application and Medusa core",
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { join } from "path"
|
||||||
|
import { ContainerRegistrationKeys, MedusaError } from "@medusajs/utils"
|
||||||
|
import { LinkLoader, logger, MedusaAppLoader } from "@medusajs/framework"
|
||||||
|
|
||||||
|
import { ensureDbExists } from "../utils"
|
||||||
|
import { initializeContainer } from "../../loaders"
|
||||||
|
import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins"
|
||||||
|
|
||||||
|
const TERMINAL_SIZE = process.stdout.columns
|
||||||
|
|
||||||
|
const main = async function ({ directory, modules }) {
|
||||||
|
try {
|
||||||
|
/**
|
||||||
|
* Setup
|
||||||
|
*/
|
||||||
|
const container = await initializeContainer(directory)
|
||||||
|
await ensureDbExists(container)
|
||||||
|
|
||||||
|
const medusaAppLoader = new MedusaAppLoader()
|
||||||
|
const configModule = container.resolve(
|
||||||
|
ContainerRegistrationKeys.CONFIG_MODULE
|
||||||
|
)
|
||||||
|
|
||||||
|
const plugins = getResolvedPlugins(directory, configModule, true) || []
|
||||||
|
const linksSourcePaths = plugins.map((plugin) =>
|
||||||
|
join(plugin.resolve, "links")
|
||||||
|
)
|
||||||
|
await new LinkLoader(linksSourcePaths).load()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generating migrations
|
||||||
|
*/
|
||||||
|
logger.info("Generating migrations...")
|
||||||
|
|
||||||
|
await medusaAppLoader.runModulesMigrations({
|
||||||
|
moduleNames: modules,
|
||||||
|
action: "generate",
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
|
logger.info("Migrations generated")
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default main
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { join } from "path"
|
||||||
|
import { ContainerRegistrationKeys } from "@medusajs/utils"
|
||||||
|
import { LinkLoader, logger, MedusaAppLoader } from "@medusajs/framework"
|
||||||
|
|
||||||
|
import { syncLinks } from "./sync-links"
|
||||||
|
import { ensureDbExists } from "../utils"
|
||||||
|
import { initializeContainer } from "../../loaders"
|
||||||
|
import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins"
|
||||||
|
|
||||||
|
const TERMINAL_SIZE = process.stdout.columns
|
||||||
|
|
||||||
|
const main = async function ({
|
||||||
|
directory,
|
||||||
|
skipLinks,
|
||||||
|
executeAllLinks,
|
||||||
|
executeSafeLinks,
|
||||||
|
}) {
|
||||||
|
try {
|
||||||
|
/**
|
||||||
|
* Setup
|
||||||
|
*/
|
||||||
|
const container = await initializeContainer(directory)
|
||||||
|
await ensureDbExists(container)
|
||||||
|
|
||||||
|
const medusaAppLoader = new MedusaAppLoader()
|
||||||
|
const configModule = container.resolve(
|
||||||
|
ContainerRegistrationKeys.CONFIG_MODULE
|
||||||
|
)
|
||||||
|
|
||||||
|
const plugins = getResolvedPlugins(directory, configModule, true) || []
|
||||||
|
const linksSourcePaths = plugins.map((plugin) =>
|
||||||
|
join(plugin.resolve, "links")
|
||||||
|
)
|
||||||
|
await new LinkLoader(linksSourcePaths).load()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run migrations
|
||||||
|
*/
|
||||||
|
logger.info("Running migrations...")
|
||||||
|
await medusaAppLoader.runModulesMigrations({
|
||||||
|
action: "run",
|
||||||
|
})
|
||||||
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
|
logger.info("Migrations completed")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync links
|
||||||
|
*/
|
||||||
|
if (!skipLinks) {
|
||||||
|
console.log(new Array(TERMINAL_SIZE).join("-"))
|
||||||
|
await syncLinks(medusaAppLoader, {
|
||||||
|
executeAll: executeAllLinks,
|
||||||
|
executeSafe: executeSafeLinks,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit()
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(error)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default main
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { join } from "path"
|
||||||
|
import { ContainerRegistrationKeys, MedusaError } from "@medusajs/utils"
|
||||||
|
import { LinkLoader, logger, MedusaAppLoader } from "@medusajs/framework"
|
||||||
|
|
||||||
|
import { ensureDbExists } from "../utils"
|
||||||
|
import { initializeContainer } from "../../loaders"
|
||||||
|
import { getResolvedPlugins } from "../../loaders/helpers/resolve-plugins"
|
||||||
|
|
||||||
|
const TERMINAL_SIZE = process.stdout.columns
|
||||||
|
|
||||||
|
const main = async function ({ directory, modules }) {
|
||||||
|
try {
|
||||||
|
/**
|
||||||
|
* Setup
|
||||||
|
*/
|
||||||
|
const container = await initializeContainer(directory)
|
||||||
|
await ensureDbExists(container)
|
||||||
|
|
||||||
|
const medusaAppLoader = new MedusaAppLoader()
|
||||||
|
const configModule = container.resolve(
|
||||||
|
ContainerRegistrationKeys.CONFIG_MODULE
|
||||||
|
)
|
||||||
|
|
||||||
|
const plugins = getResolvedPlugins(directory, configModule, true) || []
|
||||||
|
const linksSourcePaths = plugins.map((plugin) =>
|
||||||
|
join(plugin.resolve, "links")
|
||||||
|
)
|
||||||
|
await new LinkLoader(linksSourcePaths).load()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverting migrations
|
||||||
|
*/
|
||||||
|
logger.info("Reverting migrations...")
|
||||||
|
await medusaAppLoader.runModulesMigrations({
|
||||||
|
moduleNames: modules,
|
||||||
|
action: "revert",
|
||||||
|
})
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default main
|
||||||
@@ -81,6 +81,99 @@ async function askForLinkActionsToPerform(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Low-level utility to sync links. This utility is used
|
||||||
|
* by the migrate command as-well.
|
||||||
|
*/
|
||||||
|
export async function syncLinks(
|
||||||
|
medusaAppLoader: MedusaAppLoader,
|
||||||
|
{
|
||||||
|
executeAll,
|
||||||
|
executeSafe,
|
||||||
|
}: {
|
||||||
|
executeSafe: boolean
|
||||||
|
executeAll: boolean
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
const planner = await medusaAppLoader.getLinksExecutionPlanner()
|
||||||
|
|
||||||
|
logger.info("Syncing links...")
|
||||||
|
|
||||||
|
const actionPlan = await planner.createPlan()
|
||||||
|
const groupActionPlan = groupByActionPlan(actionPlan)
|
||||||
|
|
||||||
|
if (groupActionPlan.delete?.length) {
|
||||||
|
/**
|
||||||
|
* Do not delete anything when "--execute-safe" flag
|
||||||
|
* is used. And only prompt when "--execute-all"
|
||||||
|
* flag isn't used either
|
||||||
|
*/
|
||||||
|
if (executeSafe) {
|
||||||
|
groupActionPlan.delete = []
|
||||||
|
} else if (!executeAll) {
|
||||||
|
groupActionPlan.delete = await askForLinkActionsToPerform(
|
||||||
|
`Select the tables to ${chalk.red(
|
||||||
|
"DELETE"
|
||||||
|
)}. The following links have been removed`,
|
||||||
|
groupActionPlan.delete
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupActionPlan.notify?.length) {
|
||||||
|
let answer = groupActionPlan.notify
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not update anything when "--execute-safe" flag
|
||||||
|
* is used. And only prompt when "--execute-all"
|
||||||
|
* flag isn't used either.
|
||||||
|
*/
|
||||||
|
if (executeSafe) {
|
||||||
|
answer = []
|
||||||
|
} else if (!executeAll) {
|
||||||
|
answer = await askForLinkActionsToPerform(
|
||||||
|
`Select the tables to ${chalk.red(
|
||||||
|
"UPDATE"
|
||||||
|
)}. The following links have been updated`,
|
||||||
|
groupActionPlan.notify
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
groupActionPlan.update ??= []
|
||||||
|
groupActionPlan.update.push(
|
||||||
|
...answer.map((action) => {
|
||||||
|
return {
|
||||||
|
...action,
|
||||||
|
action: "update",
|
||||||
|
} as LinkMigrationsPlannerAction
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const toCreate = groupActionPlan.create ?? []
|
||||||
|
const toUpdate = groupActionPlan.update ?? []
|
||||||
|
const toDelete = groupActionPlan.delete ?? []
|
||||||
|
const actionsToExecute = [...toCreate, ...toUpdate, ...toDelete]
|
||||||
|
|
||||||
|
await planner.executePlan(actionsToExecute)
|
||||||
|
|
||||||
|
if (toCreate.length) {
|
||||||
|
logActions("Created following links tables", toCreate)
|
||||||
|
}
|
||||||
|
if (toUpdate.length) {
|
||||||
|
logActions("Updated following links tables", toUpdate)
|
||||||
|
}
|
||||||
|
if (toDelete.length) {
|
||||||
|
logActions("Deleted following links tables", toDelete)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actionsToExecute.length) {
|
||||||
|
logger.info("Links sync completed")
|
||||||
|
} else {
|
||||||
|
logger.info("Database already up-to-date")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const main = async function ({ directory, executeSafe, executeAll }) {
|
const main = async function ({ directory, executeSafe, executeAll }) {
|
||||||
try {
|
try {
|
||||||
const container = await initializeContainer(directory)
|
const container = await initializeContainer(directory)
|
||||||
@@ -98,83 +191,7 @@ const main = async function ({ directory, executeSafe, executeAll }) {
|
|||||||
)
|
)
|
||||||
await new LinkLoader(linksSourcePaths).load()
|
await new LinkLoader(linksSourcePaths).load()
|
||||||
|
|
||||||
const planner = await medusaAppLoader.getLinksExecutionPlanner()
|
await syncLinks(medusaAppLoader, { executeAll, executeSafe })
|
||||||
|
|
||||||
logger.info("Syncing links...")
|
|
||||||
|
|
||||||
const actionPlan = await planner.createPlan()
|
|
||||||
const groupActionPlan = groupByActionPlan(actionPlan)
|
|
||||||
|
|
||||||
if (groupActionPlan.delete?.length) {
|
|
||||||
/**
|
|
||||||
* Do not delete anything when "--execute-safe" flag
|
|
||||||
* is used. And only prompt when "--execute-all"
|
|
||||||
* flag isn't used either
|
|
||||||
*/
|
|
||||||
if (executeSafe) {
|
|
||||||
groupActionPlan.delete = []
|
|
||||||
} else if (!executeAll) {
|
|
||||||
groupActionPlan.delete = await askForLinkActionsToPerform(
|
|
||||||
`Select the tables to ${chalk.red(
|
|
||||||
"DELETE"
|
|
||||||
)}. The following links have been removed`,
|
|
||||||
groupActionPlan.delete
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (groupActionPlan.notify?.length) {
|
|
||||||
let answer = groupActionPlan.notify
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Do not update anything when "--execute-safe" flag
|
|
||||||
* is used. And only prompt when "--execute-all"
|
|
||||||
* flag isn't used either.
|
|
||||||
*/
|
|
||||||
if (executeSafe) {
|
|
||||||
answer = []
|
|
||||||
} else if (!executeAll) {
|
|
||||||
answer = await askForLinkActionsToPerform(
|
|
||||||
`Select the tables to ${chalk.red(
|
|
||||||
"UPDATE"
|
|
||||||
)}. The following links have been updated`,
|
|
||||||
groupActionPlan.notify
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
groupActionPlan.update ??= []
|
|
||||||
groupActionPlan.update.push(
|
|
||||||
...answer.map((action) => {
|
|
||||||
return {
|
|
||||||
...action,
|
|
||||||
action: "update",
|
|
||||||
} as LinkMigrationsPlannerAction
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const toCreate = groupActionPlan.create ?? []
|
|
||||||
const toUpdate = groupActionPlan.update ?? []
|
|
||||||
const toDelete = groupActionPlan.delete ?? []
|
|
||||||
const actionsToExecute = [...toCreate, ...toUpdate, ...toDelete]
|
|
||||||
|
|
||||||
await planner.executePlan(actionsToExecute)
|
|
||||||
|
|
||||||
if (toCreate.length) {
|
|
||||||
logActions("Created following links tables", toCreate)
|
|
||||||
}
|
|
||||||
if (toUpdate.length) {
|
|
||||||
logActions("Updated following links tables", toUpdate)
|
|
||||||
}
|
|
||||||
if (toDelete.length) {
|
|
||||||
logActions("Deleted following links tables", toDelete)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actionsToExecute.length) {
|
|
||||||
logger.info("Links sync completed")
|
|
||||||
} else {
|
|
||||||
logger.info("Database already up-to-date")
|
|
||||||
}
|
|
||||||
process.exit()
|
process.exit()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e)
|
logger.error(e)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import syncLinks from "./db/sync-links"
|
import syncLinksCmd from "./db/sync-links"
|
||||||
|
|
||||||
const main = async function (argv) {
|
const main = async function (argv) {
|
||||||
if (argv.action !== "sync") {
|
if (argv.action !== "sync") {
|
||||||
return process.exit()
|
return process.exit()
|
||||||
}
|
}
|
||||||
await syncLinks(argv)
|
await syncLinksCmd(argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default main
|
export default main
|
||||||
|
|||||||
Reference in New Issue
Block a user