Skip to main content
Glama

Prisma MCP Server

Official
by prisma
Apache 2.0
4
44,192
  • Linux
  • Apple
TSClient.ts12 kB
import type { GetPrismaClientConfig } from '@prisma/client-common' import { datamodelEnumToSchemaEnum } from '@prisma/dmmf' import type { BinaryTarget } from '@prisma/get-platform' import { ClientEngineType, EnvPaths, getClientEngineType, pathToPosix } from '@prisma/internals' import * as ts from '@prisma/ts-builders' import ciInfo from 'ci-info' import crypto from 'crypto' import indent from 'indent-string' import path from 'path' import type { O } from 'ts-toolbelt' import { DMMFHelper } from '../dmmf' // eslint-disable-next-line @typescript-eslint/no-unused-vars -- used in jsdoc import { GenerateClientOptions } from '../generateClient' import { GenericArgsInfo } from '../GenericsArgsInfo' import { buildDebugInitialization } from '../utils/buildDebugInitialization' import { buildDirname } from '../utils/buildDirname' import { buildRuntimeDataModel } from '../utils/buildDMMF' import { buildQueryCompilerWasmModule } from '../utils/buildGetQueryCompilerWasmModule' import { buildQueryEngineWasmModule } from '../utils/buildGetQueryEngineWasmModule' import { buildInjectableEdgeEnv } from '../utils/buildInjectableEdgeEnv' import { buildInlineDatasources } from '../utils/buildInlineDatasources' import { buildNFTAnnotations } from '../utils/buildNFTAnnotations' import { buildRequirePath } from '../utils/buildRequirePath' import { buildWarnEnvConflicts } from '../utils/buildWarnEnvConflicts' import { commonCodeJS, commonCodeTS } from './common' import { Count } from './Count' import { Enum } from './Enum' import { FieldRefInput } from './FieldRefInput' import { type Generable } from './Generable' import { GenerateContext } from './GenerateContext' import { InputType } from './Input' import { Model } from './Model' import { PrismaClientClass } from './PrismaClient' type RuntimeName = | 'binary' | 'library' | 'wasm-engine-edge' | 'wasm-compiler-edge' | 'edge' | 'edge-esm' | 'index-browser' | 'react-native' | 'client' | (string & {}) // workaround to also allow other strings while keeping auto-complete intact export type TSClientOptions = O.Required<GenerateClientOptions, 'runtimeBase'> & { /** More granular way to define JS runtime name */ runtimeNameJs: RuntimeName /** More granular way to define TS runtime name */ runtimeNameTs: RuntimeName /** When generating the browser client */ browser: boolean /** When we are generating an /edge client */ edge: boolean /** When we are generating a /wasm client */ wasm: boolean /** When types don't need to be regenerated */ reusedTs?: string // the entrypoint to reuse /** When js doesn't need to be regenerated */ reusedJs?: string // the entrypoint to reuse /** result of getEnvPaths call */ envPaths: EnvPaths } export class TSClient implements Generable { protected readonly dmmf: DMMFHelper protected readonly genericsInfo: GenericArgsInfo constructor(protected readonly options: TSClientOptions) { this.dmmf = new DMMFHelper(options.dmmf) this.genericsInfo = new GenericArgsInfo(this.dmmf) } public toJS(): string { const { edge, wasm, binaryPaths, generator, outputDir, datamodel: inlineSchema, runtimeBase, runtimeNameJs, datasources, copyEngine = true, reusedJs, envPaths, } = this.options if (reusedJs) { return `module.exports = { ...require('${reusedJs}') }` } const relativeEnvPaths = { rootEnvPath: envPaths.rootEnvPath && pathToPosix(path.relative(outputDir, envPaths.rootEnvPath)), schemaEnvPath: envPaths.schemaEnvPath && pathToPosix(path.relative(outputDir, envPaths.schemaEnvPath)), } // This ensures that any engine override is propagated to the generated clients config const clientEngineType = getClientEngineType(generator) generator.config.engineType = clientEngineType const binaryTargets = clientEngineType === ClientEngineType.Library ? (Object.keys(binaryPaths.libqueryEngine ?? {}) as BinaryTarget[]) : (Object.keys(binaryPaths.queryEngine ?? {}) as BinaryTarget[]) const inlineSchemaHash = crypto .createHash('sha256') .update(Buffer.from(inlineSchema, 'utf8').toString('base64')) .digest('hex') const datasourceFilePath = datasources[0].sourceFilePath const config: Omit<GetPrismaClientConfig, 'runtimeDataModel' | 'dirname'> = { generator, relativeEnvPaths, relativePath: pathToPosix(path.relative(outputDir, path.dirname(datasourceFilePath))), clientVersion: this.options.clientVersion, engineVersion: this.options.engineVersion, datasourceNames: datasources.map((d) => d.name), activeProvider: this.options.activeProvider, postinstall: this.options.postinstall, ciName: ciInfo.name ?? undefined, inlineDatasources: buildInlineDatasources(datasources), inlineSchema, inlineSchemaHash, copyEngine, } // get relative output dir for it to be preserved even after bundling, or // being moved around as long as we keep the same project dir structure. const relativeOutdir = path.relative(process.cwd(), outputDir) const code = `${commonCodeJS({ ...this.options, browser: false })} ${buildRequirePath(edge)} /** * Enums */ ${this.dmmf.schema.enumTypes.prisma?.map((type) => new Enum(type, true).toJS()).join('\n\n')} ${this.dmmf.datamodel.enums .map((datamodelEnum) => new Enum(datamodelEnumToSchemaEnum(datamodelEnum), false).toJS()) .join('\n\n')} ${new Enum( { name: 'ModelName', values: this.dmmf.mappings.modelOperations.map((m) => m.model), }, true, ).toJS()} /** * Create the Client */ const config = ${JSON.stringify(config, null, 2)} ${buildDirname(edge, relativeOutdir)} ${buildRuntimeDataModel(this.dmmf.datamodel, runtimeNameJs)} ${buildQueryEngineWasmModule(wasm, copyEngine, runtimeNameJs)} ${buildQueryCompilerWasmModule(wasm, runtimeNameJs)} ${buildInjectableEdgeEnv(edge, datasources)} ${buildWarnEnvConflicts(edge, runtimeBase, runtimeNameJs)} ${buildDebugInitialization(edge)} const PrismaClient = getPrismaClient(config) exports.PrismaClient = PrismaClient Object.assign(exports, Prisma) ${buildNFTAnnotations(edge || !copyEngine, clientEngineType, binaryTargets, relativeOutdir)} ` return code } public toTS(): string { const { reusedTs } = this.options // in some cases, we just re-export the existing types if (reusedTs) { const topExports = ts.moduleExportFrom(`./${reusedTs}`) return ts.stringify(topExports) } const context = new GenerateContext({ dmmf: this.dmmf, genericArgsInfo: this.genericsInfo, generator: this.options.generator, }) const prismaClientClass = new PrismaClientClass( context, this.options.datasources, this.options.outputDir, this.options.runtimeNameTs, this.options.browser, ) const commonCode = commonCodeTS(this.options) const modelAndTypes = Object.values(this.dmmf.typeAndModelMap).reduce((acc, modelOrType) => { if (this.dmmf.outputTypeMap.model[modelOrType.name]) { acc.push(new Model(modelOrType, context)) } return acc }, [] as Model[]) // TODO: Make this code more efficient and directly return 2 arrays const prismaEnums = this.dmmf.schema.enumTypes.prisma?.map((type) => new Enum(type, true).toTS()) const modelEnums: string[] = [] const modelEnumsAliases: string[] = [] for (const datamodelEnum of this.dmmf.datamodel.enums) { modelEnums.push(new Enum(datamodelEnumToSchemaEnum(datamodelEnum), false).toTS()) modelEnumsAliases.push( ts.stringify( ts.moduleExport(ts.typeDeclaration(datamodelEnum.name, ts.namedType(`$Enums.${datamodelEnum.name}`))), ), ts.stringify( ts.moduleExport(ts.constDeclaration(datamodelEnum.name, ts.namedType(`typeof $Enums.${datamodelEnum.name}`))), ), ) } const fieldRefs = this.dmmf.schema.fieldRefTypes.prisma?.map((type) => new FieldRefInput(type).toTS()) ?? [] const countTypes: Count[] = this.dmmf.schema.outputObjectTypes.prisma ?.filter((t) => t.name.endsWith('CountOutputType')) .map((t) => new Count(t, context)) const code = ` /** * Client **/ ${commonCode.tsWithoutNamespace()} ${modelAndTypes.map((m) => m.toTSWithoutNamespace()).join('\n')} ${ modelEnums.length > 0 ? ` /** * Enums */ export namespace $Enums { ${modelEnums.join('\n\n')} } ${modelEnumsAliases.join('\n\n')} ` : '' } ${prismaClientClass.toTSWithoutNamespace()} export namespace Prisma { ${indent( `${commonCode.ts()} ${new Enum( { name: 'ModelName', values: this.dmmf.mappings.modelOperations.map((m) => m.model), }, true, ).toTS()} ${prismaClientClass.toTS()} export type Datasource = { url?: string } /** * Count Types */ ${countTypes.map((t) => t.toTS()).join('\n')} /** * Models */ ${modelAndTypes.map((model) => model.toTS()).join('\n')} /** * Enums */ ${prismaEnums?.join('\n\n')} ${ fieldRefs.length > 0 ? ` /** * Field references */ ${fieldRefs.join('\n\n')}` : '' } /** * Deep Input Types */ ${this.dmmf.inputObjectTypes.prisma ?.reduce((acc, inputType) => { if (inputType.name.includes('Json') && inputType.name.includes('Filter')) { const needsGeneric = this.genericsInfo.typeNeedsGenericModelArg(inputType) const innerName = needsGeneric ? `${inputType.name}Base<$PrismaModel>` : `${inputType.name}Base` const typeName = needsGeneric ? `${inputType.name}<$PrismaModel = never>` : inputType.name // This generates types for JsonFilter to prevent the usage of 'path' without another parameter const baseName = `Required<${innerName}>` acc.push(`export type ${typeName} = | PatchUndefined< Either<${baseName}, Exclude<keyof ${baseName}, 'path'>>, ${baseName} > | OptionalFlat<Omit<${baseName}, 'path'>>`) acc.push(new InputType(inputType, context).overrideName(`${inputType.name}Base`).toTS()) } else { acc.push(new InputType(inputType, context).toTS()) } return acc }, [] as string[]) .join('\n')} ${this.dmmf.inputObjectTypes.model?.map((inputType) => new InputType(inputType, context).toTS()).join('\n') ?? ''} /** * Batch Payload for updateMany & deleteMany & createMany */ export type BatchPayload = { count: number } /** * DMMF */ export const dmmf: runtime.BaseDMMF `, 2, )}}` return code } public toBrowserJS(): string { const code = `${commonCodeJS({ ...this.options, runtimeNameJs: 'index-browser', browser: true, })} /** * Enums */ ${this.dmmf.schema.enumTypes.prisma?.map((type) => new Enum(type, true).toJS()).join('\n\n')} ${this.dmmf.schema.enumTypes.model?.map((type) => new Enum(type, false).toJS()).join('\n\n') ?? ''} ${new Enum( { name: 'ModelName', values: this.dmmf.mappings.modelOperations.map((m) => m.model), }, true, ).toJS()} /** * This is a stub Prisma Client that will error at runtime if called. */ class PrismaClient { constructor() { return new Proxy(this, { get(target, prop) { let message const runtime = getRuntime() if (runtime.isEdge) { message = \`PrismaClient is not configured to run in \${runtime.prettyName}. In order to run Prisma Client on edge runtime, either: - Use Prisma Accelerate: https://pris.ly/d/accelerate - Use Driver Adapters: https://pris.ly/d/driver-adapters \`; } else { message = 'PrismaClient is unable to run in this browser environment, or has been bundled for the browser (running in \`' + runtime.prettyName + '\`).' } message += \` If this is unexpected, please open an issue: https://pris.ly/prisma-prisma-bug-report\` throw new Error(message) } }) } } exports.PrismaClient = PrismaClient Object.assign(exports, Prisma) ` return code } }

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