feat(migrations): CLI generate command (#8103)
This commit is contained in:
committed by
GitHub
parent
4c2e9a3239
commit
104b00d4e9
@@ -6,6 +6,8 @@ import {
|
||||
} from "@mikro-orm/migrations"
|
||||
import { MikroORM, MikroORMOptions } from "@mikro-orm/core"
|
||||
import { PostgreSqlDriver } from "@mikro-orm/postgresql"
|
||||
import { dirname } from "path"
|
||||
import { access, mkdir, writeFile } from "fs/promises"
|
||||
|
||||
/**
|
||||
* Events emitted by the migrations class
|
||||
@@ -56,7 +58,9 @@ export class Migrations extends EventEmitter<MigrationsEvents> {
|
||||
async generate(): Promise<MigrationResult> {
|
||||
const connection = await this.#getConnection()
|
||||
const migrator = connection.getMigrator()
|
||||
|
||||
try {
|
||||
await this.ensureSnapshot(migrator["snapshotPath"])
|
||||
return await migrator.createMigration()
|
||||
} finally {
|
||||
await connection.close(true)
|
||||
@@ -134,4 +138,35 @@ export class Migrations extends EventEmitter<MigrationsEvents> {
|
||||
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,7 +1,6 @@
|
||||
import { join } from "path"
|
||||
import { setTimeout } from "timers/promises"
|
||||
import { MetadataStorage } from "@mikro-orm/core"
|
||||
import { createDatabase, dropDatabase } from "pg-god"
|
||||
|
||||
import { Migrations } from "../../index"
|
||||
import { FileSystem } from "../../../common"
|
||||
@@ -22,22 +21,12 @@ const pgGodCredentials = {
|
||||
host: DB_HOST,
|
||||
}
|
||||
|
||||
// TODO: Reenable once flakiness is taken care of
|
||||
describe.skip("Generate migrations", () => {
|
||||
describe("Generate migrations", () => {
|
||||
beforeEach(async () => {
|
||||
await dropDatabase(
|
||||
{ databaseName: dbName, errorIfNonExist: false },
|
||||
pgGodCredentials
|
||||
)
|
||||
await fs.cleanup()
|
||||
await createDatabase({ databaseName: dbName }, pgGodCredentials)
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
await dropDatabase(
|
||||
{ databaseName: dbName, errorIfNonExist: false },
|
||||
pgGodCredentials
|
||||
)
|
||||
await fs.cleanup()
|
||||
MetadataStorage.clear()
|
||||
}, 300 * 1000)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./migration-down"
|
||||
export * from "./migration-up"
|
||||
export * from "./migration-generate"
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user