Skip to main content
Glama

Prisma MCP Server

Official
by prisma
sqlite.test.ts19.7 kB
import { DbPull } from '../../commands/DbPull' import { describeMatrix, noDriverAdapters, sqliteOnly } from '../__helpers__/conditionalTests' import { createDefaultTestContext } from '../__helpers__/context' const isMacOrWindowsCI = Boolean(process.env.CI) && ['darwin', 'win32'].includes(process.platform) if (isMacOrWindowsCI) { jest.setTimeout(60_000) } const ctx = createDefaultTestContext() describeMatrix({ providers: { d1: true } }, 'D1', () => { const urlValueRegex = /url\s*=\s*".*"/ test('should succeed with listLocalDatabases() when a single local Cloudflare D1 database exists', async () => { ctx.fixture('cloudflare-d1-one-db') const introspect = new DbPull() const result = introspect.parse(['--print'], await ctx.config(), ctx.configDir()) await expect(result).resolves.toMatchInlineSnapshot(`""`) // Example values: // Windows // 'file:.wrangler//state//v3//d1//miniflare-D1DatabaseObject//5d11bcce386042472d19a6a4f58e40041ebc5932c972e1449cbf404f3e3c4a7a.sqlite' // macOS // 'file:.wrangler/state/v3/d1/miniflare-D1DatabaseObject/5d11bcce386042472d19a6a4f58e40041ebc5932c972e1449cbf404f3e3c4a7a.sqlite' expect(ctx.normalizedCapturedStdout().replace(urlValueRegex, 'url = "REPLACED_BY_TEST"')).toMatchInlineSnapshot(` "generator client { provider = "prisma-client-js" } datasource db { provider = "sqlite" } model Post { id Int @id @default(autoincrement()) title String authorId Int User User @relation(fields: [authorId], references: [id]) } model User { id Int @id @default(autoincrement()) email String @unique count1 Int name String? Post Post[] } " `) }) test('should succeed when reintrospecting with listLocalDatabases() when a single local Cloudflare D1 database exists', async () => { ctx.fixture('re-introspection/sqlite/cloudflare-d1-one-db') const introspect = new DbPull() const result = introspect.parse([], await ctx.config(), ctx.configDir()) await expect(result).resolves.toMatchInlineSnapshot(`""`) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "Prisma schema loaded from prisma/schema.prisma Datasource "db": SQLite database "5d11bcce386042472d19a6a4f58e40041ebc5932c972e1449cbf404f3e3c4a7a.sqlite" <location placeholder> - Introspecting based on datasource defined in prisma/schema.prisma ✔ Introspected 2 models and wrote them into prisma/schema.prisma in XXXms Run prisma generate to generate Prisma Client. " `) }) }) describeMatrix(sqliteOnly, 'common/sqlite', () => { test('basic introspection', async () => { ctx.fixture('introspection/sqlite') const introspect = new DbPull() const result = introspect.parse(['--print'], await ctx.config(), ctx.configDir()) await expect(result).resolves.toMatchInlineSnapshot(`""`) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "generator client { provider = "prisma-client-js" } datasource db { provider = "sqlite" } model Post { authorId Int content String? createdAt DateTime @default(now()) id Int @id @default(autoincrement()) published Boolean @default(false) title String author User @relation(fields: [authorId], references: [id], onDelete: Cascade) } model Profile { bio String? id Int @id @default(autoincrement()) userId Int @unique(map: "Profile.userId") user User @relation(fields: [userId], references: [id], onDelete: Cascade) } model User { email String @unique(map: "User.email") id Int @id @default(autoincrement()) name String? posts Post[] profile Profile? } " `) }) test('introspection --force', async () => { ctx.fixture('introspection/sqlite') const introspect = new DbPull() const result = introspect.parse(['--print', '--force'], await ctx.config(), ctx.configDir()) await expect(result).resolves.toMatchInlineSnapshot(`""`) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "generator client { provider = "prisma-client-js" } datasource db { provider = "sqlite" } model Post { authorId Int content String? createdAt DateTime @default(now()) id Int @id @default(autoincrement()) published Boolean @default(false) title String User User @relation(fields: [authorId], references: [id], onDelete: Cascade) } model Profile { bio String? id Int @id @default(autoincrement()) userId Int @unique(map: "Profile.userId") User User @relation(fields: [userId], references: [id], onDelete: Cascade) } model User { email String @unique(map: "User.email") id Int @id @default(autoincrement()) name String? Post Post[] Profile Profile? } " `) }) describeMatrix(noDriverAdapters, 'using classic engine', () => { test('basic introspection with config', async () => { ctx.fixture('introspection/sqlite') ctx.setDatasource({ url: 'file:./dev.db', }) const introspect = new DbPull() const result = introspect.parse(['--print'], await ctx.config(), ctx.configDir()) await expect(result).resolves.toBe('') expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "generator client { provider = "prisma-client-js" } datasource db { provider = "sqlite" } model Post { authorId Int content String? createdAt DateTime @default(now()) id Int @id @default(autoincrement()) published Boolean @default(false) title String author User @relation(fields: [authorId], references: [id], onDelete: Cascade) } model Profile { bio String? id Int @id @default(autoincrement()) userId Int @unique(map: "Profile.userId") user User @relation(fields: [userId], references: [id], onDelete: Cascade) } model User { email String @unique(map: "User.email") id Int @id @default(autoincrement()) name String? posts Post[] profile Profile? } " `) }) test('basic introspection with schema missing file: prefix should fail', async () => { ctx.fixture('introspection/sqlite') ctx.setDatasource({ url: 'withoutfileprefix.db', }) const introspect = new DbPull() const result = introspect.parse(['--print'], await ctx.config(), ctx.configDir()) // TODO: this error is not entirely correct: the invalid URL is in the config file, // not in the datasource block. The message needs to be updated when removing the // `url` property from the PSL. await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` "P1013 The provided database string is invalid. \`datasource.url\` in \`prisma.config.ts\` is invalid: must start with the protocol \`file:\`. " `) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` " " `) }) }) it('should succeed when schema and db do match', async () => { ctx.fixture('introspect') const result = DbPull.new().parse([], await ctx.config(), ctx.configDir()) await expect(result).resolves.toMatchInlineSnapshot(`""`) expect(ctx.mocked['console.log'].mock.calls.join('\n').replace(/\d{2,3}ms/, 'XXms')).toMatchInlineSnapshot(`""`) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "Prisma schema loaded from prisma/schema.prisma Datasource "db": SQLite database "dev.db" <location placeholder> - Introspecting based on datasource defined in prisma/schema.prisma ✔ Introspected 3 models and wrote them into prisma/schema.prisma in XXXms Run prisma generate to generate Prisma Client. " `) }) it('should succeed and keep changes to valid schema and output warnings', async () => { ctx.fixture('introspect') const result = DbPull.new().parse(['--schema=./prisma/reintrospection.prisma'], await ctx.config(), ctx.configDir()) await expect(result).resolves.toMatchInlineSnapshot(`""`) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "Prisma schema loaded from prisma/reintrospection.prisma Datasource "db": SQLite database "dev.db" <location placeholder> - Introspecting based on datasource defined in prisma/reintrospection.prisma ✔ Introspected 3 models and wrote them into prisma/reintrospection.prisma in XXXms *** WARNING *** These models were enriched with \`@@map\` information taken from the previous Prisma schema: - "AwesomeNewPost" - "AwesomeProfile" - "AwesomeUser" Run prisma generate to generate Prisma Client. " `) expect(ctx.fs.read('prisma/reintrospection.prisma')).toMatchInlineSnapshot(` "generator client { provider = "prisma-client-js" output = "../generated/client" } datasource db { provider = "sqlite" } model AwesomeUser { email String @unique(map: "User.email") id Int @id @default(autoincrement()) name String? newPosts AwesomeNewPost[] profile AwesomeProfile? @@map("User") } model AwesomeNewPost { authorId Int content String? createdAt DateTime @default(now()) id Int @id @default(autoincrement()) published Boolean @default(false) title String author AwesomeUser @relation(fields: [authorId], references: [id], onDelete: Cascade) @@map("Post") } model AwesomeProfile { bio String? id Int @id @default(autoincrement()) userId Int @unique(map: "Profile.userId") user AwesomeUser @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("Profile") } " `) }) it('should succeed and keep changes to valid schema and output warnings when using --print', async () => { ctx.fixture('introspect') const originalSchema = ctx.fs.read('prisma/reintrospection.prisma') const result = DbPull.new().parse( ['--print', '--schema=./prisma/reintrospection.prisma'], await ctx.config(), ctx.configDir(), ) await expect(result).resolves.toMatchInlineSnapshot(`""`) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "generator client { provider = "prisma-client-js" output = "../generated/client" } datasource db { provider = "sqlite" } model AwesomeUser { email String @unique(map: "User.email") id Int @id @default(autoincrement()) name String? newPosts AwesomeNewPost[] profile AwesomeProfile? @@map("User") } model AwesomeNewPost { authorId Int content String? createdAt DateTime @default(now()) id Int @id @default(autoincrement()) published Boolean @default(false) title String author AwesomeUser @relation(fields: [authorId], references: [id], onDelete: Cascade) @@map("Post") } model AwesomeProfile { bio String? id Int @id @default(autoincrement()) userId Int @unique(map: "Profile.userId") user AwesomeUser @relation(fields: [userId], references: [id], onDelete: Cascade) @@map("Profile") } " `) expect(ctx.mocked['console.error'].mock.calls.join('\n')).toMatchInlineSnapshot(` " // *** WARNING *** // // These models were enriched with \`@@map\` information taken from the previous Prisma schema: // - "AwesomeNewPost" // - "AwesomeProfile" // - "AwesomeUser" // " `) expect(ctx.fs.read('prisma/reintrospection.prisma')).toStrictEqual(originalSchema) }) it('should succeed when schema and db do not match', async () => { ctx.fixture('existing-db-histories-diverge') const result = DbPull.new().parse([], await ctx.config(), ctx.configDir()) await expect(result).resolves.toMatchInlineSnapshot(`""`) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" <location placeholder> - Introspecting based on datasource defined in prisma/schema.prisma ✔ Introspected 3 models and wrote them into prisma/schema.prisma in XXXms Run prisma generate to generate Prisma Client. " `) }) it('should fail when db is missing', async () => { ctx.fixture('schema-only-sqlite') const result = DbPull.new().parse([], await ctx.config(), ctx.configDir()) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` " P1003 The introspected database does not exist: prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. To fix this, you have two options: - manually create a database. - make sure the database connection URL inside the datasource block in schema.prisma points to an existing database. Then you can run prisma db pull again. " `) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" <location placeholder> - Introspecting based on datasource defined in prisma/schema.prisma ✖ Introspecting based on datasource defined in prisma/schema.prisma " `) }) it('should fail when db is empty', async () => { ctx.fixture('schema-only-sqlite') ctx.fs.write('dev.db', '') const result = DbPull.new().parse([], await ctx.config(), ctx.configDir()) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` " P4001 The introspected database was empty: prisma db pull could not create any models in your schema.prisma file and you will not be able to generate Prisma Client with the prisma generate command. To fix this, you have two options: - manually create a table in your database. - make sure the database connection URL inside the datasource block in schema.prisma points to a database that is not empty (it must contain at least one table). Then you can run prisma db pull again. " `) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "Prisma schema loaded from prisma/schema.prisma Datasource "my_db": SQLite database "dev.db" <location placeholder> - Introspecting based on datasource defined in prisma/schema.prisma ✖ Introspecting based on datasource defined in prisma/schema.prisma " `) }) it('should fail when Prisma schema is missing', async () => { ctx.fixture('valid-config-only') const result = DbPull.new().parse([], await ctx.config(), ctx.configDir()) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` "Could not find a schema.prisma file that is required for this command. You can either provide it with --schema, set its path in the \`schema\` property in your Prisma Config file, or put it into the default location ./prisma/schema.prisma https://pris.ly/d/prisma-schema-location" `) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(`""`) }) it('should fail when schema is invalid', async () => { ctx.fixture('introspect') const result = DbPull.new().parse(['--schema=./prisma/invalid.prisma'], await ctx.config(), ctx.configDir()) await expect(result).rejects.toThrowErrorMatchingInlineSnapshot(` "P1012 error: Error validating model "something": Each model must have at least one unique criteria that has only required fields. Either mark a single field with \`@id\`, \`@unique\` or add a multi field criterion with \`@@id([])\` or \`@@unique([])\` to the model. --> prisma/invalid.prisma:10 | 9 | 10 | model something { 11 | id Int 12 | } | Introspection failed as your current Prisma schema file is invalid Please fix your current schema manually (using either 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 --force flag to ignore your current schema and overwrite it. All local modifications will be lost. " `) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "Prisma schema loaded from prisma/invalid.prisma Datasource "db": SQLite database "dev.db" <location placeholder> - Introspecting based on datasource defined in prisma/invalid.prisma ✖ Introspecting based on datasource defined in prisma/invalid.prisma " `) }) it('should succeed when schema is invalid and using --force', async () => { ctx.fixture('introspect') const result = DbPull.new().parse( ['--schema=./prisma/invalid.prisma', '--force'], await ctx.config(), ctx.configDir(), ) await expect(result).resolves.toMatchInlineSnapshot(`""`) expect(ctx.normalizedCapturedStdout()).toMatchInlineSnapshot(` "Prisma schema loaded from prisma/invalid.prisma Datasource "db": SQLite database "dev.db" <location placeholder> - Introspecting based on datasource defined in prisma/invalid.prisma ✔ Introspected 3 models and wrote them into prisma/invalid.prisma in XXXms Run prisma generate to generate Prisma Client. " `) expect(ctx.fs.read('prisma/invalid.prisma')).toMatchInlineSnapshot(` "generator client { provider = "prisma-client-js" output = "../generated/client" } datasource db { provider = "sqlite" } model Post { authorId Int content String? createdAt DateTime @default(now()) id Int @id @default(autoincrement()) published Boolean @default(false) title String User User @relation(fields: [authorId], references: [id], onDelete: Cascade) } model Profile { bio String? id Int @id @default(autoincrement()) userId Int @unique(map: "Profile.userId") User User @relation(fields: [userId], references: [id], onDelete: Cascade) } model User { email String @unique(map: "User.email") id Int @id @default(autoincrement()) name String? Post Post[] Profile Profile? } " `) }) })

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