PrismaNamespaceFile.ts•7.48 kB
import * as ts from '@prisma/ts-builders'
import { commonCodeTS } from '../common'
import { Datasources } from '../Datasources'
import { Enum } from '../Enum'
import { FieldRefInput } from '../FieldRefInput'
import { GenerateContext } from '../GenerateContext'
import { globalOmitConfig } from '../globalOmit'
import type { TSClientOptions } from '../TSClient'
import { clientTypeMapDefinition } from '../TypeMap'
const jsDocHeader = `/*
 * WARNING: This is an internal file that is subject to change!
 *
 * 🛑 Under no circumstances should you import this file directly! 🛑
 *
 * All exports from this file are wrapped under a \`Prisma\` namespace object in the client.ts file.
 * While this enables partial backward compatibility, it is not part of the stable public API.
 *
 * If you are looking for your Models, Enums, and Input Types, please import them from the respective
 * model files in the \`model\` directory!
 */
`
export function createPrismaNamespaceFile(context: GenerateContext, options: TSClientOptions): string {
  const imports = [
    ts.moduleImport(context.runtimeImport).asNamespace('runtime'),
    ts.moduleImport(context.importFileName(`../models`)).asNamespace('Prisma').typeOnly(),
    ts.moduleImport(context.importFileName(`./class`)).named(ts.namedImport('PrismaClient').typeOnly()),
  ].map((i) => ts.stringify(i))
  const prismaEnums = context.dmmf.schema.enumTypes.prisma?.map((type) => new Enum(type, true).toTS())
  const fieldRefs = context.dmmf.schema.fieldRefTypes.prisma?.map((type) => new FieldRefInput(type).toTS()) ?? []
  return `${jsDocHeader}
${imports.join('\n')}
export type * from '${context.importFileName(`../models`)}'
${commonCodeTS(options)}
${new Enum(
  {
    name: 'ModelName',
    values: context.dmmf.mappings.modelOperations.map((m) => m.model),
  },
  true,
).toTS()}
${clientTypeMapDefinition(context)}
/**
 * Enums
 */
${prismaEnums?.join('\n\n')}
${
  fieldRefs.length > 0
    ? `
/**
 * Field references
 */
${fieldRefs.join('\n\n')}`
    : ''
}
/**
 * Batch Payload for updateMany & deleteMany & createMany
 */
export type BatchPayload = {
  count: number
}
${new Datasources(options.datasources).toTS()}
${clientExtensionsDefinitions()}
export type DefaultPrismaClient = PrismaClient
export type ErrorFormat = 'pretty' | 'colorless' | 'minimal'
${ts.stringify(ts.moduleExport(buildClientOptions(context, options)))}
${ts.stringify(globalOmitConfig(context.dmmf))}
/* Types for Logging */
export type LogLevel = 'info' | 'query' | 'warn' | 'error'
export type LogDefinition = {
  level: LogLevel
  emit: 'stdout' | 'event'
}
export type CheckIsLogLevel<T> = T extends LogLevel ? T : never;
export type GetLogType<T> = CheckIsLogLevel<
  T extends LogDefinition ? T['level'] : T
>;
export type GetEvents<T extends any[]> = T extends Array<LogLevel | LogDefinition>
  ? GetLogType<T[number]>
  : never;
export type QueryEvent = {
  timestamp: Date
  query: string
  params: string
  duration: number
  target: string
}
export type LogEvent = {
  timestamp: Date
  message: string
  target: string
}
/* End Types for Logging */
export type PrismaAction =
  | 'findUnique'
  | 'findUniqueOrThrow'
  | 'findMany'
  | 'findFirst'
  | 'findFirstOrThrow'
  | 'create'
  | 'createMany'
  | 'createManyAndReturn'
  | 'update'
  | 'updateMany'
  | 'updateManyAndReturn'
  | 'upsert'
  | 'delete'
  | 'deleteMany'
  | 'executeRaw'
  | 'queryRaw'
  | 'aggregate'
  | 'count'
  | 'runCommandRaw'
  | 'findRaw'
  | 'groupBy'
/**
 * \`PrismaClient\` proxy available in interactive transactions.
 */
export type TransactionClient = Omit<DefaultPrismaClient, runtime.ITXClientDenyList>
`
}
function clientExtensionsDefinitions() {
  const define = ts.moduleExport(
    ts.constDeclaration('defineExtension').setValue(
      ts
        .namedValue('runtime.Extensions.defineExtension')
        .as(ts.namedType('unknown'))
        .as(
          ts
            .namedType('runtime.Types.Extensions.ExtendsHook')
            .addGenericArgument(ts.stringLiteral('define'))
            .addGenericArgument(ts.namedType('TypeMapCb'))
            .addGenericArgument(ts.namedType('runtime.Types.Extensions.DefaultArgs')),
        ),
    ),
  )
  return ts.stringify(define)
}
function buildClientOptions(context: GenerateContext, options: TSClientOptions) {
  const clientOptions = ts
    .interfaceDeclaration('PrismaClientOptions')
    .add(
      ts
        .property('datasources', ts.namedType('Datasources'))
        .optional()
        .setDocComment(ts.docComment('Overwrites the datasource url from your schema.prisma file')),
    )
    .add(
      ts
        .property('datasourceUrl', ts.stringType)
        .optional()
        .setDocComment(ts.docComment('Overwrites the datasource url from your schema.prisma file')),
    )
    .add(
      ts
        .property('errorFormat', ts.namedType('ErrorFormat'))
        .optional()
        .setDocComment(ts.docComment('@default "colorless"')),
    )
    .add(
      ts.property('log', ts.array(ts.unionType([ts.namedType('LogLevel'), ts.namedType('LogDefinition')]))).optional()
        .setDocComment(ts.docComment`
             @example
             \`\`\`
             // Shorthand for \`emit: 'stdout'\`
             log: ['query', 'info', 'warn', 'error']
             // Emit as events only
             log: [
               { emit: 'event', level: 'query' },
               { emit: 'event', level: 'info' },
               { emit: 'event', level: 'warn' }
               { emit: 'event', level: 'error' }
             ]
            // Emit as events and log to stdout
            log: [
              { emit: 'stdout', level: 'query' },
              { emit: 'stdout', level: 'info' },
              { emit: 'stdout', level: 'warn' }
              { emit: 'stdout', level: 'error' }
            ]
             \`\`\`
             Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/logging#the-log-option).
          `),
    )
  const transactionOptions = ts
    .objectType()
    .add(ts.property('maxWait', ts.numberType).optional())
    .add(ts.property('timeout', ts.numberType).optional())
  if (context.dmmf.hasEnumInNamespace('TransactionIsolationLevel', 'prisma')) {
    transactionOptions.add(ts.property('isolationLevel', ts.namedType('TransactionIsolationLevel')).optional())
  }
  clientOptions.add(
    ts.property('transactionOptions', transactionOptions).optional().setDocComment(ts.docComment`
             The default values for transactionOptions
             maxWait ?= 2000
             timeout ?= 5000
          `),
  )
  if (['library', 'client', 'wasm-compiler-edge', 'wasm-engine-edge'].includes(options.runtimeName)) {
    clientOptions.add(
      ts
        .property('adapter', ts.unionType([ts.namedType('runtime.SqlDriverAdapterFactory'), ts.namedType('null')]))
        .optional()
        .setDocComment(
          ts.docComment('Instance of a Driver Adapter, e.g., like one provided by `@prisma/adapter-planetscale`'),
        ),
    )
  }
  clientOptions.add(
    ts.property('omit', ts.namedType('GlobalOmitConfig')).optional().setDocComment(ts.docComment`
        Global configuration for omitting model fields by default.
        @example
        \`\`\`
        const prisma = new PrismaClient({
          omit: {
            user: {
              password: true
            }
          }
        })
        \`\`\`
      `),
  )
  return clientOptions
}