Skip to main content
Glama
prisma

Prisma MCP Server

Official
by prisma
DbPull.ts11.2 kB
import type { PrismaConfigInternal } from '@prisma/config' import Debug from '@prisma/debug' import { arg, checkUnsupportedDataProxy, Command, createSchemaPathInput, format, formatms, getCommandWithExecutor, getConfig, HelpError, inferDirectoryConfig, link, loadSchemaContext, MigrateTypes, printSchemaLoadedMessage, relativizePathInPSLError, toSchemasContainer, validatePrismaConfigWithDatasource, } from '@prisma/internals' import { bold, dim, green, italic, red, underline, yellow } from 'kleur/colors' import path from 'path' import { Migrate } from '../Migrate' import type { EngineArgs } from '../types' import { countModelsAndTypes } from '../utils/countModelsAndTypes' import { parseDatasourceInfo } from '../utils/ensureDatabaseExists' import { NoSchemaFoundError } from '../utils/errors' import { isSchemaEmpty } from '../utils/isSchemaEmpty' import { printDatasource } from '../utils/printDatasource' import { printIntrospectedSchema } from '../utils/printIntrospectedSchema' import { removeSchemaFiles } from '../utils/removeSchemaFiles' import { saveSchemaFiles } from '../utils/saveSchemaFiles' import { createSpinner } from '../utils/spinner' const debug = Debug('prisma:db:pull') export class DbPull implements Command { public static new(): DbPull { return new DbPull() } private static help = format(` Pull the state from the database to the Prisma schema using introspection ${bold('Usage')} ${dim('$')} prisma db pull [flags/options] The datasource URL configuration is read from the Prisma config file (e.g., ${italic('prisma.config.ts')}). ${bold('Flags')} -h, --help Display this help message --force Ignore current Prisma schema file --print Print the introspected Prisma schema to stdout ${bold('Options')} --config Custom path to your Prisma config file --schema Custom path to your Prisma schema --composite-type-depth Specify the depth for introspecting composite types (e.g. Embedded Documents in MongoDB) Number, default is -1 for infinite depth, 0 = off --schemas Specify the database schemas to introspect. This overrides the schemas defined in the datasource block of your Prisma schema. --local-d1 Generate a Prisma schema from a local Cloudflare D1 database ${bold('Examples')} With an existing Prisma schema ${dim('$')} prisma db pull Or specify a Prisma schema path ${dim('$')} prisma db pull --schema=./schema.prisma Instead of saving the result to the filesystem, you can also print it to stdout ${dim('$')} prisma db pull --print Overwrite the current schema with the introspected schema instead of enriching it ${dim('$')} prisma db pull --force Set composite types introspection depth to 2 levels ${dim('$')} prisma db pull --composite-type-depth=2 `) public async parse( argv: string[], config: PrismaConfigInternal, baseDir: string = process.cwd(), ): Promise<string | Error> { const args = arg(argv, { '--help': Boolean, '-h': '--help', '--print': Boolean, '--schema': String, '--config': String, '--schemas': String, '--force': Boolean, '--composite-type-depth': Number, // optional, only on mongodb }) const spinnerFactory = createSpinner(!args['--print']) if (args instanceof Error) { return this.help(args.message) } if (args['--help']) { return this.help() } const schemaContext = await loadSchemaContext({ schemaPath: createSchemaPathInput({ schemaPathFromArgs: args['--schema'], schemaPathFromConfig: config.schema, baseDir, }), printLoadMessage: false, allowNull: true, }) const cmd = 'db pull' const validatedConfig = validatePrismaConfigWithDatasource({ config, cmd }) checkUnsupportedDataProxy({ cmd, validatedConfig }) // Print to console if --print is not passed to only have the schema in stdout if (schemaContext && !args['--print']) { printSchemaLoadedMessage(schemaContext.loadedFromPathForLogMessages) printDatasource({ datasourceInfo: parseDatasourceInfo(schemaContext?.primaryDatasource, validatedConfig) }) } if (!schemaContext) { throw new NoSchemaFoundError() } const firstDatasource = schemaContext.primaryDatasource const schema = schemaContext.schemaFiles await getConfig({ datamodel: schema, }) // Re-Introspection is not supported on MongoDB const modelRegex = /\s*model\s*(\w+)\s*{/ const isReintrospection = schema.some(([_, schema]) => !!modelRegex.exec(schema as string)) if (isReintrospection && !args['--force'] && firstDatasource?.provider === 'mongodb') { throw new Error(`Iterating on one schema using re-introspection with db pull is currently not supported with MongoDB provider. You can explicitly ignore and override your current local schema file with ${green( getCommandWithExecutor('prisma db pull --force'), )} Some information will be lost (relations, comments, mapped fields, @ignore...), follow ${link( 'https://github.com/prisma/prisma/issues/9585', )} for more info.`) } const migrate = await Migrate.setup({ schemaEngineConfig: config, baseDir, schemaContext, extensions: config['extensions'], }) const engine = migrate.engine const basedOn = firstDatasource ? ` based on datasource defined in ${underline(schemaContext.loadedFromPathForLogMessages)}` : '' const introspectionSpinner = spinnerFactory(`Introspecting${basedOn}`) const before = Math.round(performance.now()) let introspectionSchema: MigrateTypes.SchemasContainer | undefined = undefined let introspectionWarnings: EngineArgs.IntrospectResult['warnings'] try { const directoryConfig = inferDirectoryConfig(schemaContext, config) const introspectionResult = await engine.introspect({ schema: toSchemasContainer(schema), baseDirectoryPath: schemaContext?.schemaRootDir ?? process.cwd(), viewsDirectoryPath: directoryConfig.viewsDirPath, force: args['--force'], compositeTypeDepth: args['--composite-type-depth'], namespaces: args['--schemas']?.split(','), }) introspectionSchema = introspectionResult.schema introspectionWarnings = introspectionResult.warnings debug(`Introspection warnings`, introspectionWarnings) } catch (e: any) { introspectionSpinner.failure() /** * Human-friendly error handling based on: * https://www.prisma.io/docs/reference/api-reference/error-reference */ if (e.code === 'P4001' && isSchemaEmpty(introspectionSchema)) { /* P4001: The introspected database was empty */ throw new Error(`\n${red(bold(`${e.code} `))}${red('The introspected database was empty:')} ${bold('prisma db pull')} could not create any models in your ${bold( 'schema.prisma', )} file and you will not be able to generate Prisma Client with the ${bold( getCommandWithExecutor('prisma generate'), )} command. ${bold('To fix this, you have two options:')} - manually create a table in your database. - make sure the database connection URL inside the ${bold('datasource')} block in ${bold( 'schema.prisma', )} points to a database that is not empty (it must contain at least one table). Then you can run ${green(getCommandWithExecutor('prisma db pull'))} again. `) } else if (e.code === 'P1003') { /* P1003: Database does not exist */ throw new Error(`\n${red(bold(`${e.code} `))}${red('The introspected database does not exist:')} ${bold('prisma db pull')} could not create any models in your ${bold( 'schema.prisma', )} file and you will not be able to generate Prisma Client with the ${bold( getCommandWithExecutor('prisma generate'), )} command. ${bold('To fix this, you have two options:')} - manually create a database. - make sure the database connection URL inside the ${bold('datasource')} block in ${bold( 'schema.prisma', )} points to an existing database. Then you can run ${green(getCommandWithExecutor('prisma db pull'))} again. `) } else if (e.code === 'P1012') { /* P1012: Schema parsing error */ process.stdout.write('\n') // empty line const message = relativizePathInPSLError(e.message) throw new Error(`${red(message)} Introspection failed as your current Prisma schema file is invalid Please fix your current schema manually (using either ${green( getCommandWithExecutor('prisma validate'), )} or the Prisma VS Code extension to understand what's broken and confirm you fixed it), and then run this command again. Or run this command with the ${green( '--force', )} flag to ignore your current schema and overwrite it. All local modifications will be lost.\n`) } process.stdout.write('\n') // empty line throw e } const introspectionWarningsMessage = this.getWarningMessage(introspectionWarnings) if (args['--print']) { printIntrospectedSchema(introspectionSchema, process.stdout) if (introspectionWarningsMessage.trim().length > 0) { // Replace make it a // comment block console.error(introspectionWarningsMessage.replace(/(\n)/gm, '\n// ')) } } else { if (args['--force']) { await removeSchemaFiles(schema) } await saveSchemaFiles(introspectionSchema) const { modelsCount, typesCount } = countModelsAndTypes(introspectionSchema) const modelsCountMessage = `${modelsCount} ${modelsCount > 1 ? 'models' : 'model'}` const typesCountMessage = `${typesCount} ${typesCount > 1 ? 'embedded documents' : 'embedded document'}` let modelsAndTypesMessage: string if (typesCount > 0) { modelsAndTypesMessage = `${modelsCountMessage} and ${typesCountMessage}` } else { modelsAndTypesMessage = `${modelsCountMessage}` } const modelsAndTypesCountMessage = modelsCount + typesCount > 1 ? `${modelsAndTypesMessage} and wrote them` : `${modelsAndTypesMessage} and wrote it` const introspectedSchemaPath = schemaContext?.loadedFromPathForLogMessages || introspectionSchema.files[0].path introspectionSpinner.success(`Introspected ${modelsAndTypesCountMessage} into ${underline( path.relative(process.cwd(), introspectedSchemaPath), )} in ${bold(formatms(Math.round(performance.now()) - before))} ${yellow(introspectionWarningsMessage)} ${`Run ${green(getCommandWithExecutor('prisma generate'))} to generate Prisma Client.`}`) } return '' } private getWarningMessage(warnings: EngineArgs.IntrospectResult['warnings']): string { if (warnings) { return `\n${warnings}` } return '' } public help(error?: string): string | HelpError { if (error) { return new HelpError(`\n${bold(red(`!`))} ${error}\n${DbPull.help}`) } return DbPull.help } }

Latest Blog Posts

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