Skip to main content
Glama

Prisma MCP Server

Official
by prisma
Apache 2.0
4
44,192
  • Linux
  • Apple
MigrateDev.ts12.2 kB
import path from 'node:path' import type { PrismaConfigInternal } from '@prisma/config' import Debug from '@prisma/debug' import { arg, canPrompt, checkUnsupportedDataProxy, Command, format, getCommandWithExecutor, HelpError, inferDirectoryConfig, isError, loadEnvFile, loadSchemaContext, MigrateTypes, validate, } from '@prisma/internals' import { bold, dim, green, red } from 'kleur/colors' import prompt from 'prompts' import { Migrate } from '../Migrate' import type { EngineResults } from '../types' import type { DatasourceInfo } from '../utils/ensureDatabaseExists' import { ensureDatabaseExists, parseDatasourceInfo } from '../utils/ensureDatabaseExists' import { MigrateDevEnvNonInteractiveError } from '../utils/errors' import { handleUnexecutableSteps } from '../utils/handleEvaluateDataloss' import { printDatasource } from '../utils/printDatasource' import { printFilesFromMigrationIds } from '../utils/printFiles' import { printMigrationId } from '../utils/printMigrationId' import { getMigrationName } from '../utils/promptForMigrationName' import { executeSeedCommand, getSeedCommandFromPackageJson } from '../utils/seed' const debug = Debug('prisma:migrate:dev') export class MigrateDev implements Command { public static new(): MigrateDev { return new MigrateDev() } private static help = format(` ${ process.platform === 'win32' ? '' : '🏋️ ' }Create a migration from changes in Prisma schema, apply it to the database, trigger generators (e.g. Prisma Client) ${bold('Usage')} ${dim('$')} prisma migrate dev [options] ${bold('Options')} -h, --help Display this help message --config Custom path to your Prisma config file --schema Custom path to your Prisma schema -n, --name Name the migration --create-only Create a new migration but do not apply it The migration will be empty if there are no changes in Prisma schema --skip-generate Skip triggering generators (e.g. Prisma Client) --skip-seed Skip triggering seed ${bold('Examples')} Create a migration from changes in Prisma schema, apply it to the database, trigger generators (e.g. Prisma Client) ${dim('$')} prisma migrate dev Specify a schema ${dim('$')} prisma migrate dev --schema=./schema.prisma Create a migration without applying it ${dim('$')} prisma migrate dev --create-only `) public async parse(argv: string[], config: PrismaConfigInternal): Promise<string | Error> { const args = arg(argv, { '--help': Boolean, '-h': '--help', '--name': String, '-n': '--name', // '--force': Boolean, // '-f': '--force', '--create-only': Boolean, '--schema': String, '--config': String, '--skip-generate': Boolean, '--skip-seed': Boolean, '--telemetry-information': String, }) if (isError(args)) { return this.help(args.message) } if (args['--help']) { return this.help() } await loadEnvFile({ schemaPath: args['--schema'], printMessage: true, config }) const schemaContext = await loadSchemaContext({ schemaPathFromArg: args['--schema'], schemaPathFromConfig: config.schema, schemaEngineConfig: config, }) const { migrationsDirPath } = inferDirectoryConfig(schemaContext, config) checkUnsupportedDataProxy({ cmd: 'migrate dev', schemaContext }) const datasourceInfo = parseDatasourceInfo(schemaContext.primaryDatasource) const adapter = config.engine === 'js' ? await config.adapter() : undefined printDatasource({ datasourceInfo, adapter }) process.stdout.write('\n') // empty line // Validate schema (same as prisma validate) validate({ schemas: schemaContext.schemaFiles }) let wasDbCreated: string | undefined // `ensureDatabaseExists` is not compatible with WebAssembly. // TODO: check why the output and error handling here is different than in `MigrateDeploy`. if (!adapter) { // Automatically create the database if it doesn't exist wasDbCreated = await ensureDatabaseExists(schemaContext.primaryDatasource) if (wasDbCreated) { process.stdout.write(wasDbCreated + '\n\n') } } const schemaFilter: MigrateTypes.SchemaFilter = { externalTables: config.tables?.external ?? [], externalEnums: config.enums?.external ?? [], } const migrate = await Migrate.setup({ schemaEngineConfig: config, migrationsDirPath, schemaContext, schemaFilter, shadowDbInitScript: config.migrations?.initShadowDb, extensions: config['extensions'], }) let devDiagnostic: EngineResults.DevDiagnosticOutput try { devDiagnostic = await migrate.devDiagnostic() debug({ devDiagnostic: JSON.stringify(devDiagnostic, null, 2) }) } catch (e) { await migrate.stop() throw e } const migrationIdsApplied: string[] = [] if (devDiagnostic.action.tag === 'reset') { this.logResetReason({ datasourceInfo, reason: devDiagnostic.action.reason, }) process.stdout.write( '\n' + `You may use ${red('prisma migrate reset')} to drop the development database.\n` + `${bold(red('All data will be lost.'))}\n`, ) await migrate.stop() // Return SIGINT exit code to signal that the process was cancelled. process.exit(130) } try { const { appliedMigrationNames } = await migrate.applyMigrations() migrationIdsApplied.push(...appliedMigrationNames) // Inform user about applied migrations now if (appliedMigrationNames.length > 0) { process.stdout.write( `\nThe following migration(s) have been applied:\n\n${printFilesFromMigrationIds( 'migrations', appliedMigrationNames, { 'migration.sql': '', }, )}\n`, ) } } catch (e) { await migrate.stop() throw e } let evaluateDataLossResult: EngineResults.EvaluateDataLossOutput try { evaluateDataLossResult = await migrate.evaluateDataLoss() debug({ evaluateDataLossResult }) } catch (e) { await migrate.stop() throw e } // display unexecutableSteps // throws error if not create-only const unexecutableStepsError = handleUnexecutableSteps( evaluateDataLossResult.unexecutableSteps, args['--create-only'], ) if (unexecutableStepsError) { await migrate.stop() throw new Error(unexecutableStepsError) } // log warnings and prompt user to continue if needed if (evaluateDataLossResult.warnings && evaluateDataLossResult.warnings.length > 0) { process.stdout.write(bold(`\n⚠️ Warnings for the current datasource:\n\n`)) for (const warning of evaluateDataLossResult.warnings) { process.stdout.write(` • ${warning.message}\n`) } process.stdout.write('\n') // empty line if (!args['--force']) { if (!canPrompt()) { await migrate.stop() throw new MigrateDevEnvNonInteractiveError() } const message = args['--create-only'] ? 'Are you sure you want to create this migration?' : 'Are you sure you want to create and apply this migration?' const confirmation = await prompt({ type: 'confirm', name: 'value', message, }) if (!confirmation.value) { process.stdout.write('Migration cancelled.\n') await migrate.stop() // Return SIGINT exit code to signal that the process was cancelled. process.exit(130) } } } let migrationName: undefined | string = undefined if (evaluateDataLossResult.migrationSteps > 0 || args['--create-only']) { const getMigrationNameResult = await getMigrationName(args['--name']) if (getMigrationNameResult.userCancelled) { process.stdout.write(getMigrationNameResult.userCancelled + '\n') await migrate.stop() // Return SIGINT exit code to signal that the process was cancelled. process.exit(130) } else { migrationName = getMigrationNameResult.name } } let migrationIds: string[] try { const createMigrationResult = await migrate.createMigration({ migrationName: migrationName || '', draft: args['--create-only'] ? true : false, schema: migrate.getPrismaSchema(), }) debug({ createMigrationResult }) if (args['--create-only']) { await migrate.stop() return `Prisma Migrate created the following migration without applying it ${printMigrationId( createMigrationResult.generatedMigrationName!, )}\n\nYou can now edit it and apply it by running ${green(getCommandWithExecutor('prisma migrate dev'))}.` } const { appliedMigrationNames } = await migrate.applyMigrations() migrationIds = appliedMigrationNames } finally { // Stop engine await migrate.stop() } // For display only, empty line migrationIdsApplied.length > 0 && process.stdout.write('\n') if (migrationIds.length === 0) { if (migrationIdsApplied.length > 0) { process.stdout.write(`${green('Your database is now in sync with your schema.')}\n`) } else { process.stdout.write(`Already in sync, no schema change or pending migration was found.\n`) } } else { // e.g., "./prisma/custom-migrations" const migrationsDirPathRelative = path.relative(process.cwd(), migrationsDirPath) process.stdout.write( `\nThe following migration(s) have been created and applied from new schema changes:\n\n${printFilesFromMigrationIds( migrationsDirPathRelative, migrationIds, { 'migration.sql': '', }, )} ${green('Your database is now in sync with your schema.')}\n`, ) } // Run if not skipped if (!process.env.PRISMA_MIGRATE_SKIP_GENERATE && !args['--skip-generate']) { await migrate.tryToRunGenerate(datasourceInfo) process.stdout.write('\n') // empty line } // If database was created we want to run the seed if not skipped if (wasDbCreated && !process.env.PRISMA_MIGRATE_SKIP_SEED && !args['--skip-seed']) { try { const seedCommandFromPrismaConfig = config.migrations?.seed const seedCommandFromPkgJson = await getSeedCommandFromPackageJson(process.cwd()) const seedCommand = seedCommandFromPrismaConfig ?? seedCommandFromPkgJson if (seedCommand) { process.stdout.write('\n') // empty line const successfulSeeding = await executeSeedCommand({ commandFromConfig: seedCommand }) if (successfulSeeding) { process.stdout.write(`\n${process.platform === 'win32' ? '' : '🌱 '}The seed command has been executed.\n`) } else { process.exit(1) } } } catch (e) { console.error(e) } } return '' } private logResetReason({ datasourceInfo, reason }: { datasourceInfo: DatasourceInfo; reason: string }) { // Log the reason of why a reset is needed to the user process.stdout.write(reason + '\n') let message: string if (['PostgreSQL', 'SQL Server'].includes(datasourceInfo.prettyProvider!)) { if (datasourceInfo.schemas?.length) { message = `We need to reset the following schemas: "${datasourceInfo.schemas.join(', ')}"` } else if (datasourceInfo.schema) { message = `We need to reset the "${datasourceInfo.schema}" schema` } else { message = `We need to reset the database schema` } } else { message = `We need to reset the ${datasourceInfo.prettyProvider} database "${datasourceInfo.dbName}"` } if (datasourceInfo.dbLocation) { message += ` at "${datasourceInfo.dbLocation}"` } process.stdout.write(`${message}\n`) } public help(error?: string): string | HelpError { if (error) { return new HelpError(`\n${bold(red(`!`))} ${error}\n${MigrateDev.help}`) } return MigrateDev.help } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/prisma/prisma'

If you have feedback or need assistance with the MCP directory API, please join our Discord server