Skip to main content
Glama

Prisma MCP Server

Official
by prisma
Apache 2.0
4
44,213
  • Linux
  • Apple
pdp.ts13.7 kB
/* eslint-disable @typescript-eslint/no-redundant-type-constituents */ import { randomBytes } from 'crypto' import { expectTypeOf } from 'expect-type' import https from 'https' import testMatrix from './_matrix' // @ts-ignore import type { Prisma as PrismaNamespace, PrismaClient } from './generated/prisma/client' declare let prisma: PrismaClient declare let Prisma: typeof PrismaNamespace /** * Tests for underlying query component features used by Prisma Accelerate */ testMatrix.setupTestSuite(() => { let mockedRequest: jest.SpyInstance<any> const randomId1 = randomBytes(12).toString('hex') const randomId2 = randomBytes(12).toString('hex') beforeAll(async () => { // this also warms up the dataproxy (schema upload) await prisma.user.create({ data: { id: randomId1, email: 'john@doe.io', firstName: 'John', lastName: 'Doe', }, }) // this also warms up the dataproxy (schema upload) await prisma.user.create({ data: { id: randomId2, email: 'max@mustermann.io', firstName: 'Max', lastName: 'Mustermann', }, }) }) beforeEach(() => { if (typeof globalThis['fetch'] === 'function') { mockedRequest = jest.spyOn(globalThis as any, 'fetch') } else { mockedRequest = jest.spyOn(https, 'request') } }) afterEach(() => { mockedRequest.mockRestore() }) test('_runtimeDataModel is available on the client instance and provides model info', () => { const extension = Prisma.defineExtension((client) => { return prisma.$extends({ model: { $allModels: { subscribe() { expect(client).toHaveProperty('_runtimeDataModel') expect((client as any)._runtimeDataModel).toHaveProperty('models') expect((client as any)._runtimeDataModel.models).toHaveProperty('User') expect((client as any)._runtimeDataModel.models.User).toHaveProperty('dbName') expect((client as any)._runtimeDataModel.models.User).toHaveProperty('fields') expect((client as any)._runtimeDataModel.models.User.fields[3]).toHaveProperty('name') expect((client as any)._runtimeDataModel.models.User.fields[3]).toHaveProperty('kind') expect((client as any)._runtimeDataModel.models.User.fields[3]).toHaveProperty('type') expect((client as any)._runtimeDataModel.models.User.fields[4]).toHaveProperty('relationName') expect((client as any)._runtimeDataModel.models.User.fields[3]).toHaveProperty('dbName') }, }, }, }) }) prisma.$extends(extension).user.subscribe() expect.hasAssertions() }) testIf(process.env.TEST_DATA_PROXY !== undefined)( 'Prisma-Engine-Hash headers is present when sending a request', async () => { const xprisma = prisma.$extends({ query: { $allModels: { findUnique(operation) { const { __internalParams, query, args } = operation as any as { query: (...args: any[]) => Promise<any> __internalParams: any args: any } __internalParams.customDataProxyFetch = (fetch) => { return async (url, options) => { const res = await fetch(url, options) expect(res).toHaveProperty('headers') expect(res.headers.get('content-length')).toBeDefined() expect(res.headers.get('Prisma-Engine-Hash')).toBeNull() return res } } return query(args, __internalParams) }, }, }, }) const data = await xprisma.user.findUnique({ where: { id: randomId1 } }) expect(data).toHaveProperty('id', randomId1) expect(mockedRequest.mock.calls[0][1].headers).toHaveProperty( 'Prisma-Engine-Hash', '0000000000000000000000000000000000000000', ) }, ) testIf(process.env.TEST_DATA_PROXY !== undefined)('changing http headers via custom fetch', async () => { const xprisma = prisma.$extends({ query: { $allModels: { findUnique(operation) { const { __internalParams, query, args } = operation as any as { query: (...args: any[]) => Promise<any> __internalParams: any args: any } __internalParams.customDataProxyFetch = (fetch) => { return async (url, options) => { options.headers = { ...options.headers, 'x-custom-header': 'hello', } const res = await fetch(url, options) expect(res).toHaveProperty('headers') expect(res.headers.get('content-length')).toBeDefined() return res } } return query(args, __internalParams) }, }, }, }) const data = await xprisma.user.findUnique({ where: { id: randomId1 } }) expect(data).toHaveProperty('id', randomId1) expect(mockedRequest.mock.calls[0][1].headers).toHaveProperty('x-custom-header', 'hello') }) testIf(process.env.TEST_DATA_PROXY !== undefined)( 'confirm that custom fetch cascades like a middleware', async () => { const xprisma = prisma .$extends({ query: { $allModels: { findUnique(operation) { const { __internalParams, query, args } = operation as any as { query: (...args: any[]) => Promise<any> __internalParams: any args: any } __internalParams.customDataProxyFetch = (fetch) => { return (url, args) => fetch(url, { ...args, order: [1] }) } return query(args, __internalParams) }, }, }, }) .$extends({ query: { $allModels: { findUnique(operation) { const { __internalParams, query, args } = operation as any as { query: (...args: any[]) => Promise<any> __internalParams: any args: any } __internalParams.customDataProxyFetch = (fetch) => { return (url, args) => fetch(url, { ...args, order: [...args.order, 2] }) } return query(args, __internalParams) }, }, }, }) .$extends({ query: { $allModels: { findUnique(operation) { const { __internalParams, query, args } = operation as any as { query: (...args: any[]) => Promise<any> __internalParams: any args: any } __internalParams.customDataProxyFetch = (fetch) => { return (url, args) => { expect(args.order).toEqual([1, 2]) return fetch(url, args) } } return query(args, __internalParams) }, }, }, }) const data = await xprisma.user.findUnique({ where: { id: randomId1 } }).catch() expect(data).toHaveProperty('id', randomId1) }, ) testIf(process.env.TEST_DATA_PROXY !== undefined)( 'allows to override customDataProxyFetch for the whole batch', async () => { const xprisma = prisma.$extends({ query: { // @ts-expect-error async $__internalBatch({ query, args, __internalParams }) { let cacheInfo: null | string = null __internalParams.customDataProxyFetch = (fetch) => (url, args) => { cacheInfo = 'hit!' return fetch(url, args) } const result = await query(args, __internalParams) for (const item of result) { if (item) { item.cacheInfo = cacheInfo } } return result }, }, }) const [user1, user2] = await Promise.all([ xprisma.user.findUnique({ where: { id: randomId1 } }), xprisma.user.findUnique({ where: { id: randomId2 } }), ]) expect(user1).toHaveProperty('cacheInfo', 'hit!') expect(user2).toHaveProperty('cacheInfo', 'hit!') }, ) testIf(process.env.TEST_DATA_PROXY !== undefined)( 'an overridden method can call its parent and the itx is respected', async () => { await prisma .$extends({ model: { $allModels: { findFirst(args: any) { const ctx = Prisma.getExtensionContext(this) expectTypeOf(ctx).toHaveProperty('$parent').toEqualTypeOf<unknown | undefined>() expectTypeOf(ctx).toHaveProperty('name').toEqualTypeOf<string | undefined>() expectTypeOf(ctx).toHaveProperty('$name').toEqualTypeOf<string | undefined>() return ctx.$parent![ctx.name!].findFirst({ ...args }) }, }, }, }) .$transaction(async (tx) => { await tx.user.create({ data: { email: 'jane@doe.io', firstName: 'Jane', lastName: 'Doe', }, }) const data = await tx.user.findFirst({ where: { email: 'jane@doe.io', }, select: { email: true, }, }) // data is visible within the transaction expect(data.email).toEqual('jane@doe.io') throw new Error('rollback') // try rollback }) .catch((e) => { expect(e.message).toEqual('rollback') }) const users = await prisma.user.findMany() // default amount, rollback worked expect(users).toHaveLength(2) expect.assertions(3) }, ) testIf(process.env.TEST_DATA_PROXY !== undefined)( 'an overridden method can call its parent and the itx with a query extension is respected', async () => { await prisma .$extends({ query: { $allModels: { findFirst({ query, args }) { expect(args).toHaveProperty('__accelerateInfo', 'info') const { __accelerateInfo, ...rest } = args as any return query(rest) }, }, }, }) .$extends({ model: { $allModels: { findFirst(args: any) { const ctx = Prisma.getExtensionContext(this) expectTypeOf(ctx).toHaveProperty('$parent').toEqualTypeOf<unknown | undefined>() expectTypeOf(ctx).toHaveProperty('name').toEqualTypeOf<string | undefined>() expectTypeOf(ctx).toHaveProperty('$name').toEqualTypeOf<string | undefined>() return ctx.$parent![ctx.name!].findFirst({ ...args, __accelerateInfo: 'info', }) }, }, }, }) .$transaction(async (tx) => { await tx.user.create({ data: { email: 'jane@doe.io', firstName: 'Jane', lastName: 'Doe', }, }) const data = await tx.user.findFirst({ where: { email: 'jane@doe.io', }, select: { email: true, }, }) // data is visible within the transaction expect(data.email).toEqual('jane@doe.io') throw new Error('rollback') // try rollback }) .catch((e) => { expect(e.message).toEqual('rollback') }) const users = await prisma.user.findMany() // default amount, rollback worked expect(users).toHaveLength(2) expect.assertions(4) }, ) testIf(process.env.TEST_DATA_PROXY !== undefined)('customDataProxyFetch for batches stacks', async () => { expect.assertions(2) const xprisma = prisma .$extends({ query: { // @ts-expect-error $__internalBatch({ query, args, __internalParams }) { __internalParams.customDataProxyFetch = (fetch) => (url, args) => { return fetch(url, { ...args, order: [1] }) } return query(args, __internalParams) }, }, }) .$extends({ query: { // @ts-expect-error $__internalBatch({ query, args, __internalParams }) { __internalParams.customDataProxyFetch = (fetch) => (url, args) => { expect(args.order).toEqual([1]) return fetch(url, { ...args, order: [...args.order, 2] }) } return query(args, __internalParams) }, }, }) .$extends({ query: { // @ts-expect-error $__internalBatch({ query, args, __internalParams }) { __internalParams.customDataProxyFetch = (fetch) => (url, args) => { expect(args.order).toEqual([1, 2]) return fetch(url, args) } return query(args, __internalParams) }, }, }) await Promise.all([ xprisma.user.findUnique({ where: { id: randomId1 } }), xprisma.user.findUnique({ where: { id: randomId2 } }), ]) }) })

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