|
| 1 | +import { defineCommand } from 'citty' |
| 2 | +import { consola } from 'consola' |
| 3 | +import { execa } from 'execa' |
| 4 | +import { readFile } from 'node:fs/promises' |
| 5 | +import { join } from 'pathe' |
| 6 | +import { createDrizzleClient, getDatabaseMigrationFiles, AppliedDatabaseMigrationsQuery } from '../../../dist/module.mjs' |
| 7 | +import { sql } from 'drizzle-orm' |
| 8 | + |
| 9 | +export default defineCommand({ |
| 10 | + meta: { |
| 11 | + name: 'mark-as-migrated', |
| 12 | + description: 'Mark local database migration(s) as applied to the database.' |
| 13 | + }, |
| 14 | + args: { |
| 15 | + name: { |
| 16 | + type: 'positional', |
| 17 | + description: 'The name of the migration to mark as applied.', |
| 18 | + required: false |
| 19 | + }, |
| 20 | + cwd: { |
| 21 | + type: 'option', |
| 22 | + description: 'The directory to run the command in.', |
| 23 | + required: false |
| 24 | + }, |
| 25 | + verbose: { |
| 26 | + alias: 'v', |
| 27 | + type: 'boolean', |
| 28 | + description: 'Show verbose output.', |
| 29 | + required: false |
| 30 | + } |
| 31 | + }, |
| 32 | + async run({ args }) { |
| 33 | + if (args.verbose) { |
| 34 | + consola.level = 'debug' |
| 35 | + } |
| 36 | + const cwd = args.cwd || process.cwd() |
| 37 | + consola.info('Ensuring database schema is generated...') |
| 38 | + await execa({ |
| 39 | + stdout: 'pipe', |
| 40 | + preferLocal: true, |
| 41 | + cwd |
| 42 | + })`nuxt prepare` |
| 43 | + const hubConfig = JSON.parse(await readFile(join(cwd, '.nuxt/hub/database/config.json'), 'utf-8')) |
| 44 | + consola.info(`Database dialect: \`${hubConfig.database.dialect}\``) |
| 45 | + const localMigrations = await getDatabaseMigrationFiles(hubConfig) |
| 46 | + if (localMigrations.length === 0) { |
| 47 | + consola.info('No local migrations found.') |
| 48 | + return |
| 49 | + } |
| 50 | + consola.info(`Found \`${localMigrations.length}\` local migration${localMigrations.length === 1 ? '' : 's'}`) |
| 51 | + consola.debug(`Local migrations:\n${localMigrations.map(migration => `- ${migration.name}`).join('\n')}`) |
| 52 | + if (args.name && !localMigrations.find(migration => migration.name === args.name)) { |
| 53 | + consola.error(`Local migration \`${args.name}\` not found.`) |
| 54 | + process.exit(1) |
| 55 | + } |
| 56 | + const db = await createDrizzleClient(hubConfig.database) |
| 57 | + const execute = hubConfig.database.dialect === 'sqlite' ? 'run' : 'execute' |
| 58 | + const { rows: appliedMigrations } = await db[execute](sql.raw(AppliedDatabaseMigrationsQuery)) |
| 59 | + consola.info(`Database has \`${appliedMigrations.length}\` applied migration${appliedMigrations.length === 1 ? '' : 's'}`) |
| 60 | + consola.debug(`Applied migrations:\n${appliedMigrations.map(migration => `- ${migration.name} (\`${migration.applied_at}\`)`).join('\n')}`) |
| 61 | + // If a specific migration is provided, check if it is already applied |
| 62 | + if (args.name && appliedMigrations.find(appliedMigration => appliedMigration.name === args.name)) { |
| 63 | + consola.success(`Local migration \`${args.name}\` is already applied.`) |
| 64 | + return |
| 65 | + } |
| 66 | + // If a specific migration is provided, mark it as applied |
| 67 | + if (args.name) { |
| 68 | + await db[execute](sql.raw(`INSERT INTO "_hub_migrations" (name) values ('${args.name}');`)) |
| 69 | + consola.success(`Local migration \`${args.name}\` marked as applied.`) |
| 70 | + return |
| 71 | + } |
| 72 | + // If no specific migration is provided, mark all pending migrations as applied |
| 73 | + const pendingMigrations = localMigrations.filter(migration => !appliedMigrations.find(appliedMigration => appliedMigration.name === migration.name)) |
| 74 | + if (pendingMigrations.length === 0) { |
| 75 | + consola.success('All migrations are already applied.') |
| 76 | + return |
| 77 | + } |
| 78 | + consola.info(`Found \`${pendingMigrations.length}\` pending migration${pendingMigrations.length === 1 ? '' : 's'}`) |
| 79 | + let migrationsMarkedAsApplied = 0 |
| 80 | + for (const migration of pendingMigrations) { |
| 81 | + const confirmed = await consola.prompt(`Mark migration \`${migration.name}\` as applied?`, { |
| 82 | + type: 'confirm', |
| 83 | + default: true, |
| 84 | + cancel: 'null' |
| 85 | + }) |
| 86 | + if (!confirmed) { |
| 87 | + consola.info(`Migration \`${migration.name}\` skipped.`) |
| 88 | + continue |
| 89 | + } |
| 90 | + await db[execute](sql.raw(`INSERT INTO "_hub_migrations" (name) values ('${migration.name}');`)) |
| 91 | + consola.success(`Migration \`${migration.name}\` marked as applied.`) |
| 92 | + migrationsMarkedAsApplied++ |
| 93 | + } |
| 94 | + if (migrationsMarkedAsApplied === 0) { |
| 95 | + consola.info('No migrations marked as applied.') |
| 96 | + return |
| 97 | + } |
| 98 | + consola.success(`${migrationsMarkedAsApplied} migration${migrationsMarkedAsApplied === 1 ? '' : 's'} marked as applied.`) |
| 99 | + } |
| 100 | +}) |
0 commit comments