Skip to main content
Glama

Prisma MCP Server

Official
by prisma
Apache 2.0
4
44,192
  • Linux
  • Apple
Input.ts6.05 kB
import { uniqueBy } from '@prisma/client-common' import type * as DMMF from '@prisma/dmmf' import * as ts from '@prisma/ts-builders' import indent from 'indent-string' import { GenericArgsInfo } from '../GenericsArgsInfo' import { appendSkipType } from '../utils' import { GraphQLScalarToJSTypeTable, JSOutputTypeToInputType } from '../utils/common' import { TAB_SIZE } from './constants' import { GenerateContext } from './GenerateContext' export class InputField { constructor( protected readonly field: DMMF.SchemaArg, protected readonly context: GenerateContext, protected readonly source?: string, ) {} public toTS(): string { const property = buildInputField(this.field, this.context, this.source) return ts.stringify(property) } } export function buildInputField(field: DMMF.SchemaArg, context: GenerateContext, source?: string): ts.Property { const tsType = buildAllFieldTypes(field.inputTypes, context, source) const tsProperty = ts.property(field.name, field.isRequired ? tsType : appendSkipType(context, tsType)) if (!field.isRequired) { tsProperty.optional() } const docComment = ts.docComment() if (field.comment) { docComment.addText(field.comment) } if (field.deprecation) { docComment.addText(`@deprecated since ${field.deprecation.sinceVersion}: ${field.deprecation.reason}`) } if (docComment.lines.length > 0) { tsProperty.setDocComment(docComment) } return tsProperty } function buildSingleFieldType(t: DMMF.InputTypeRef, genericsInfo: GenericArgsInfo, source?: string): ts.TypeBuilder { let type: ts.NamedType const scalarType = GraphQLScalarToJSTypeTable[t.type] if (t.location === 'enumTypes' && t.namespace === 'model') { type = ts.namedType(`$Enums.${t.type}`) } else if (t.type === 'Null') { return ts.nullType } else if (Array.isArray(scalarType)) { const union = ts.unionType(scalarType.map(namedInputType)) if (t.isList) { return union.mapVariants((variant) => ts.array(variant)) } return union } else if (t.namespace === 'prisma') { type = namedInputType(`Prisma.${t.type}`) } else { type = namedInputType(scalarType ?? t.type) } if (genericsInfo.typeRefNeedsGenericModelArg(t)) { if (source) { type.addGenericArgument(ts.stringLiteral(source)) } else { type.addGenericArgument(ts.namedType('$PrismaModel')) } } if (t.isList) { return ts.array(type) } return type } function namedInputType(typeName: string) { const typeNameParts = typeName.split('.') const typeNameWithoutNamespace = typeNameParts[typeNameParts.length - 1] const mappedInputTypeName = JSOutputTypeToInputType[typeNameWithoutNamespace] ?? typeNameWithoutNamespace return ts.namedType(typeNameParts.slice(0, -1).concat(mappedInputTypeName).join('.')) } /** * Examples: * T[], T => T | T[] * T, U => XOR<T,U> * T[], T, U => XOR<T, U> | T[] * T[], U => T[] | U * T, U, null => XOR<T,U> | null * T, U, V, W, null => XOR<T, XOR<U, XOR<V, W>>> | null * * 1. Separate XOR and non XOR items (objects and non-objects) * 2. Generate them out and `|` them */ function buildAllFieldTypes( inputTypes: readonly DMMF.InputTypeRef[], context: GenerateContext, source?: string, ): ts.TypeBuilder { const inputObjectTypes = inputTypes.filter((t) => t.location === 'inputObjectTypes' && !t.isList) const otherTypes = inputTypes.filter((t) => t.location !== 'inputObjectTypes' || t.isList) const tsInputObjectTypes = inputObjectTypes.map((type) => buildSingleFieldType(type, context.genericArgsInfo, source)) const tsOtherTypes = otherTypes.map((type) => buildSingleFieldType(type, context.genericArgsInfo, source)) if (tsOtherTypes.length === 0) { return xorTypes(tsInputObjectTypes) } if (tsInputObjectTypes.length === 0) { return ts.unionType(tsOtherTypes) } return ts.unionType(xorTypes(tsInputObjectTypes)).addVariants(tsOtherTypes) } function xorTypes(types: ts.TypeBuilder[]) { return types.reduce((prev, curr) => ts.namedType('Prisma.XOR').addGenericArgument(prev).addGenericArgument(curr)) } export class InputType { private generatedName: string constructor( protected readonly type: DMMF.InputType, protected readonly context: GenerateContext, ) { this.generatedName = type.name } public toTS(): string { const { type } = this const source = type.meta?.source const fields = uniqueBy(type.fields, (f) => f.name) // TO DISCUSS: Should we rely on TypeScript's error messages? const body = `{ ${indent( fields .map((arg) => { return new InputField(arg, this.context, source).toTS() }) .join('\n'), TAB_SIZE, )} }` const needsGeneric = this.context.genericArgsInfo.typeNeedsGenericModelArg(this.type) const typeName = needsGeneric ? `${this.type.name}<$PrismaModel = never>` : this.type.name if (type.name.includes('Json') && type.name.includes('Filter')) { const innerName = needsGeneric ? `${this.type.name}Base<$PrismaModel>` : `${this.type.name}Base` // This generates types for JsonFilter to prevent the usage of 'path' without another parameter const baseName = `Required<${innerName}>` return ` export type ${typeName} = | Prisma.PatchUndefined< Prisma.Either<${baseName}, Exclude<keyof ${baseName}, 'path'>>, ${baseName} > | Prisma.OptionalFlat<Omit<${baseName}, 'path'>> export type ${this.type.name}Base${needsGeneric ? '<$PrismaModel = never>' : ''} = ${wrapWithAtLeast(body, type)}` } else { return ` export type ${typeName} = ${wrapWithAtLeast(body, type)}` } } } /** * Wraps an input type with `Prisma.AtLeast` * @param body type string to wrap * @param input original input type * @returns */ function wrapWithAtLeast(body: string, input: DMMF.InputType) { if (input.constraints?.fields && input.constraints.fields.length > 0) { const fields = input.constraints.fields.map((f) => `"${f}"`).join(' | ') return `Prisma.AtLeast<${body}, ${fields}>` } return body }

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