feat: move migrations commands to the new db namespace (#8810)

This commit is contained in:
Harminder Virk
2024-08-27 16:40:00 +05:30
committed by GitHub
parent 6470168526
commit 2a5ee970e6
6 changed files with 334 additions and 79 deletions

View File

@@ -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: "db:sync-links",
desc: "Sync database schema with the links defined by your application and Medusa core",

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 }) {
try {
const container = await initializeContainer(directory)
@@ -98,83 +191,7 @@ const main = async function ({ directory, executeSafe, executeAll }) {
)
await new LinkLoader(linksSourcePaths).load()
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")
}
await syncLinks(medusaAppLoader, { executeAll, executeSafe })
process.exit()
} catch (e) {
logger.error(e)

View File

@@ -1,10 +1,10 @@
import syncLinks from "./db/sync-links"
import syncLinksCmd from "./db/sync-links"
const main = async function (argv) {
if (argv.action !== "sync") {
return process.exit()
}
await syncLinks(argv)
await syncLinksCmd(argv)
}
export default main