Skip to content

Commit

Permalink
fix typescript compiler crash
Browse files Browse the repository at this point in the history
  • Loading branch information
millsp committed Dec 16, 2022
1 parent 3bb4237 commit c18ede7
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 66 deletions.
2 changes: 1 addition & 1 deletion packages/client/scripts/default-index.d.ts
Expand Up @@ -42,7 +42,7 @@ export declare type PrismaClientExtends<ExtArgs extends runtime.Types.Extensions
Args extends runtime.Types.Extensions.Args = { result: R; model: M; query: Q; client: C }
>(args: ((client: PrismaClientExtends<ExtArgs>) => { $extends: { extArgs: Args } }) | {
result?: R; model?: M; query?: Q; client?: C
}) => PrismaClientExtends<runtime.Types.Extensions.MergeArgs<Args, ExtArgs, string, false>>)
}) => PrismaClientExtends<runtime.Types.Utils.PatchDeep<Args, ExtArgs>>)
}

export declare const dmmf: any
Expand Down
3 changes: 1 addition & 2 deletions packages/client/src/generation/TSClient/Model.ts
Expand Up @@ -322,7 +322,6 @@ export type ${getSelectName(model.name)}${ifExtensions(
)} = ${ifExtensions(() => `runtime.Types.Extensions.GetResultSelect<`, '')}{
${indent(
outputType.fields
.filter((field) => ifExtensions(field.outputType.location === 'outputObjectTypes', true))
.map((f) => {
const fieldTypeName = (f.outputType.type as DMMF.OutputType).name
return (
Expand All @@ -335,7 +334,7 @@ ${indent(
.join('\n'),
TAB_SIZE,
)}
}${ifExtensions(() => ` & ${getSelectName(model.name)}Scalar, ExtArgs['result']['${lowerCase(model.name)}']>`, '')}
}${ifExtensions(() => `, ExtArgs['result']['${lowerCase(model.name)}']>`, '')}
${ifExtensions(() => {
return `
export type ${getSelectName(model.name)}Scalar = {
Expand Down
88 changes: 53 additions & 35 deletions packages/client/src/generation/TSClient/PrismaClient.ts
Expand Up @@ -12,6 +12,7 @@ import { Datasources } from './Datasources'
import type { Generatable } from './Generatable'
import { getModelActions } from './utils/getModelActions'
import { ifExtensions } from './utils/ifExtensions'
import { Patch, Patch3 } from './utils/Patch'

function clientExtensionsResultDefinition(this: PrismaClientClass) {
const modelNames = Object.keys(this.dmmf.getModelMap())
Expand Down Expand Up @@ -72,45 +73,46 @@ function clientExtensionsModelDefinition(this: PrismaClientClass) {
function clientExtensionsQueryDefinition(this: PrismaClientClass) {
const modelNames = Object.keys(this.dmmf.getModelMap())

const prismaNamespaceDefinitions = `export type TypeMap<ExtArgs extends runtime.Types.Extensions.Args = runtime.Types.Extensions.DefaultArgs> = {${modelNames.reduce(
(acc, modelName) => {
const prismaNamespaceDefinitions = `export type TypeMap<ExtArgs extends runtime.Types.Extensions.Args = runtime.Types.Extensions.DefaultArgs> = {
model: {${modelNames.reduce((acc, modelName) => {
const actions = getModelActions(this.dmmf, modelName)
return `${acc}
${modelName}: {${actions.reduce((acc, action) => {
${modelName}: {${actions.reduce((acc, action) => {
return `${acc}
${action}: {
args: Prisma.${getModelArgName(modelName, action)}<ExtArgs>,
result: runtime.Types.Utils.OptionalFlat<${modelName}>
}`
${action}: {
args: Prisma.${getModelArgName(modelName, action)}<ExtArgs>,
result: runtime.Types.Utils.OptionalFlat<${modelName}>
}`
}, '')}
}`
},
'',
)}
}`
}, '')}
}
}`

const queryCbDefinition = (modelName: string, operationName: string) => {
const queryArgs = `runtime.Types.Extensions.ReadonlySelector<Prisma.TypeMap<ExtArgs>[${modelName}][${operationName}]['args']>`
const queryResult = `Prisma.TypeMap<ExtArgs>[${modelName}][${operationName}]['result']`
const inputQuery = `{ model: ${modelName}, operation: ${operationName}, args: ${queryArgs} }`
const inputQueryCb = `${inputQuery} & { query: (args: ${queryArgs}) => PrismaPromise<${queryResult}> }`
const queryArgs = `runtime.Types.Extensions.ReadonlySelector<Prisma.TypeMap<ExtArgs>['model'][${modelName}][${operationName}]['args']>`
const queryResult = `Prisma.TypeMap<ExtArgs>['model'][${modelName}][${operationName}]['result']`
const inputQueryBase = `model: ${modelName}, operation: ${operationName}, args: ${queryArgs}`
const inputQueryCbBase = `query: (args: ${queryArgs}) => PrismaPromise<${queryResult}>`
const inputQuery = `{ ${inputQueryBase}, ${inputQueryCbBase} }`

return `(args: ${inputQueryCb}) => Promise<${queryResult}>`
return `(args: ${inputQuery}) => Promise<${queryResult}>`
}

const allOperationsParam = (modelNames: string[], indent: string) => {
const key = modelNames.length > 1 ? `keyof Prisma.TypeMap<ExtArgs>` : `'${modelNames[0]}'`
const modelName = modelNames.map((mn) => `'${mn}'`).join(' | ')

return `{
${indent}$allOperations?: ${queryCbDefinition(key, `keyof Prisma.TypeMap<ExtArgs>[${key}]`)}
${indent}$allOperations?: ${queryCbDefinition(modelName, `keyof Prisma.TypeMap['model'][${modelName}]`)}
${indent}}`
}

const modelParam = (propName: string, modelNames: string[]) => {
const key = modelNames.length > 1 ? `keyof Prisma.TypeMap<ExtArgs>` : `'${modelNames[0]}'`
const key = modelNames.map((mn) => `'${mn}'`).join(' | ')

return `${propName}?: {
[K in keyof Prisma.TypeMap<ExtArgs>[${key}]]?: ${queryCbDefinition(key, `K`)}
[K in keyof Prisma.TypeMap['model'][${key}]]?: ${queryCbDefinition(key, `K`)}
} & ${allOperationsParam(modelNames, ' ')}`
}

Expand Down Expand Up @@ -145,33 +147,48 @@ function clientExtensionsHookDefinition(this: PrismaClientClass, name: '$extends
const query = clientExtensionsQueryDefinition.call(this)
const lcModelNames = Object.keys(this.dmmf.getModelMap()).map(lowerCase)
const modelNameUnion = lcModelNames.map((m) => `'${m}'`).join(' | ')
const genericParams = [result.genericParams, model.genericParams, query.genericParams, client.genericParams]
const genericVars = genericParams.map((gp) => gp.replace(/ extends .*/g, ','))

return {
signature: `${name === 'defineExtension' ? name : `${name}: { extArgs: ExtArgs } & (`}<
${result.genericParams},
${model.genericParams},
${query.genericParams},
${client.genericParams},
${genericParams.join(',\n ')},
Args extends runtime.Types.Extensions.Args = { result: R, model: M, query: Q, client: C },${
name === 'defineExtension'
? `
ExtArgs extends runtime.Types.Extensions.Args = runtime.Types.Extensions.DefaultArgs,`
: ''
}
>(extension: ((client: ${
name === 'defineExtension' ? 'PrismaClient' : 'this'
}) => { $extends: { extArgs: Args } }) | {
name?: string,
result?: R & ${result.params}
model?: M & ${model.params}
query?: ${query.params}
client?: C & ${client.params}
})${name === 'defineExtension' ? ':' : '=>'} ${
name === 'defineExtension' ? 'Prisma.DefaultPrismaClient' : 'this'
}) => { $extends: { extArgs: Args } }) | Prisma.ExtensionArgs<
ExtArgs,
${genericVars.join('\n ').slice(0, -1)}
>) ${name === 'defineExtension' ? ':' : '=>'} ${
name === 'defineExtension'
? '(client: any) => PrismaClient<any, any, any, Args>'
: `runtime.Types.Extensions.GetClient<PrismaClient<T, U, GlobalReject, runtime.Types.Extensions.MergeArgs<Args, ExtArgs, ${modelNameUnion}>>, Args['client'], ExtArgs['client']>`
: `runtime.Types.Extensions.GetClient<PrismaClient<T, U, GlobalReject, {
result: '$allModels' extends keyof Args['result']
? { [K in ${modelNameUnion}]: ${Patch3(`Args['result'][K]`, `Args['result']['$allModels']`, `ExtArgs['result'][K]`)} }
: { [K in (keyof Args['result'] | keyof ExtArgs['result'])]: ${Patch(`Args['result'][K]`, `ExtArgs['result'][K]`)} }
model: '$allModels' extends keyof Args['model']
? { [K in ${modelNameUnion}]: ${Patch3(`Args['model'][K]`, `Args['model']['$allModels']`, `ExtArgs['model'][K]`)} }
: { [K in (keyof Args['model'] | keyof ExtArgs['model'])]: ${Patch(`Args['model'][K]`, `ExtArgs['model'][K]`)} }
client: ${Patch(`Args['client']`, `ExtArgs['client']`)}
query: {}
}>, Args['client'], ExtArgs['client']>`
}${name === 'defineExtension' ? '' : ')'};`,
prismaNamespaceDefinitions: `${query.prismaNamespaceDefinitions}`,
prismaNamespaceDefinitions: `${query.prismaNamespaceDefinitions}
export type ExtensionArgs<
ExtArgs extends runtime.Types.Extensions.Args,
${genericParams.join(',\n ')}
> = {
name?: string,
result?: R & ${result.params}
model?: M & ${model.params}
query?: ${query.params}
client?: C & ${client.params}
}`,
}
}

Expand Down Expand Up @@ -444,6 +461,7 @@ get ${methodName}(): ${ifExtensions(
public toTS(): string {
return `${new Datasources(this.internalDatasources).toTS()}
${this.clientExtensionsDefinitions.prismaNamespaceDefinitions}
export type DefaultPrismaClient = PrismaClient
export type RejectOnNotFound = boolean | ((error: Error) => Error)
export type RejectPerModel = { [P in ModelName]?: RejectOnNotFound }
export type RejectPerOperation = { [P in "findUnique" | "findFirst"]?: RejectPerModel | RejectOnNotFound }
Expand Down Expand Up @@ -587,7 +605,7 @@ export function getLogLevel(log: Array<LogLevel | LogDefinition>): LogLevel | un
/**
* \`PrismaClient\` proxy available in interactive transactions.
*/
export type TransactionClient = Omit<PrismaClient, '$connect' | '$disconnect' | '$on' | '$transaction' | '$use'>
export type TransactionClient = Omit<Prisma.DefaultPrismaClient, '$connect' | '$disconnect' | '$on' | '$transaction' | '$use'>
`
}
}
4 changes: 4 additions & 0 deletions packages/client/src/generation/TSClient/utils/Patch.ts
Expand Up @@ -3,3 +3,7 @@ import { Omit } from './Omit'
export function Patch(O1: string, O2: string, KName = 'P') {
return `(${O1}) & ${Omit(O2, `keyof (${O1})`, KName)}`
}

export function Patch3(O1: string, O2: string, O3: string, KName = 'P') {
return `(${O1}) & ${Omit(O2, `keyof (${O1})`, KName)} & ${Omit(O3, `keyof (${O1}) | keyof (${O2})`, KName)}`
}
34 changes: 8 additions & 26 deletions packages/client/src/runtime/core/types/Extensions.ts
@@ -1,43 +1,25 @@
/* eslint-disable prettier/prettier */
import { RequiredArgs as Args } from '../extensions/$extends'
import { Omit, PatchFlat3,Pick, } from './Utils'
import { Omit, ReadonlyDeep } from './Utils'

export type DefaultArgs = { result: {}; model: {}; query: {}; client: {} }

export type GetResultPayload<Base extends object, R extends Args['result'][string]> =
PatchFlat3<{}, { [K in keyof R]: ReturnType<R[K]['compute']> }, Base>
{} extends R ? Base : { [K in keyof R]: ReturnType<R[K]['compute']> } & { [K in Exclude<keyof Base, keyof R>]: Base[K] }

export type GetResultSelect<Base extends object, R extends Args['result'][string]> =
Base & { [K in keyof R]?: true }
R extends unknown ? Base & { [K in keyof R]?: boolean } : never

export type GetModel<Base extends object, M extends Args['model'][string]> =
PatchFlat3<M, Base, {}>
M & Omit<Base, keyof M>

export type GetClient<Base extends object, C extends Args['client'], CP extends Args['client']> =
PatchFlat3<C, CP, Omit<Base, '$use'>>
C & Omit<CP, keyof C> & Omit<Base, '$use' | keyof C | keyof CP>

export type ReadonlySelector<T> = {
readonly [K in keyof T as K extends 'include' | 'select' ? K : never]: ReadonlySelector<T[K]>
export type ReadonlySelector<T> = T extends unknown ? {
readonly [K in keyof T as K extends 'include' | 'select' ? K : never]: ReadonlyDeep<T[K]>
} & {
[K in keyof T as K extends 'include' | 'select' ? never : K]: T[K]
}

export type MergeArgs<
ExtArgs extends Args,
PrevExtArgs extends Args,
ModelNames extends string,
ApplyAllModels extends boolean = true,
> = {
result: '$allModels' extends keyof ExtArgs['result'] ? ApplyAllModels extends true
? { [K in ModelNames]: PatchFlat3<ExtArgs['result'][K], ExtArgs['result']['$allModels'], PrevExtArgs['result'][K]> }
: { [K in keyof ExtArgs['result'] | keyof PrevExtArgs['result']]: PatchFlat3<ExtArgs['result'][K], PrevExtArgs['result'][K], {}> }
: { [K in keyof ExtArgs['result'] | keyof PrevExtArgs['result']]: PatchFlat3<ExtArgs['result'][K], PrevExtArgs['result'][K], {}> }
model: '$allModels' extends keyof ExtArgs['model'] ? ApplyAllModels extends true
? { [K in ModelNames]: PatchFlat3<ExtArgs['model'][K], ExtArgs['model']['$allModels'], PrevExtArgs['model'][K]> }
: { [K in keyof ExtArgs['model'] | keyof PrevExtArgs['model']]: PatchFlat3<ExtArgs['model'][K], PrevExtArgs['model'][K], {}> }
: { [K in keyof ExtArgs['model'] | keyof PrevExtArgs['model']]: PatchFlat3<ExtArgs['model'][K], PrevExtArgs['model'][K], {}> }
client: Pick<PatchFlat3<ExtArgs['client'], PrevExtArgs['client'], {}>, `$${string}`>
query: {}
}
} : never

export type { Args }
4 changes: 4 additions & 0 deletions packages/client/src/runtime/core/types/Utils.ts
Expand Up @@ -48,3 +48,7 @@ export type Compute<T> = T extends Function
export type OptionalFlat<T> = {
[K in keyof T]?: T[K]
}

export type ReadonlyDeep<T> = {
readonly [K in keyof T]: ReadonlyDeep<T[K]>
}
@@ -1,6 +1,38 @@
import { foreignKeyForProvider, idForProvider } from '../../../_utils/idForProvider'
import testMatrix from '../_matrix'

function createModelToManyField(times: number) {
const models: string[] = []
for (let i = 0; i < times; i++) {
models.push(`myModel${i} MyModel${i}[]`)
}

return models.join('\n')
}

function createModel(times: number, provider: string) {
const models: string[] = []
for (let i = 0; i < times; i++) {
models.push(`model MyModel${i} {
id ${idForProvider(provider)}
${createModelField(10)}
user User @relation(fields: [userId], references: [id])
userId String
}`)
}

return models.join('\n')
}

function createModelField(times: number) {
const fields: string[] = []
for (let i = 0; i < times; i++) {
fields.push(`myField${i} String`)
}

return fields.join('\n')
}

export default testMatrix.setupSchema(({ provider }) => {
return /* Prisma */ `
generator client {
Expand All @@ -19,12 +51,16 @@ export default testMatrix.setupSchema(({ provider }) => {
firstName String
lastName String
posts Post[]
${createModelToManyField(20)}
}
model Post {
id ${idForProvider(provider)}
user User @relation(fields: [userId], references: [id])
userId ${foreignKeyForProvider(provider)}
}
// the following models aren't used in the tests, but are here to test the performance of the extension
${createModel(20, provider)}
`
})
11 changes: 9 additions & 2 deletions packages/client/tests/functional/extensions/enabled/query.ts
Expand Up @@ -50,6 +50,10 @@ testMatrix.setupTestSuite(
query: {
user: {
findFirst({ args, query, operation, model }) {
if (args.select != undefined) {
// @ts-expect-error
args.select.email = undefined
}
// @ts-expect-error
args.include = undefined
// @ts-expect-error
Expand Down Expand Up @@ -675,7 +679,8 @@ testMatrix.setupTestSuite(
expectTypeOf(args).not.toBeAny
expectTypeOf(query).toBeFunction()
expectTypeOf(operation).toEqualTypeOf<'findFirst'>()
expectTypeOf(model).toEqualTypeOf<'Post' | 'User'>()
type Model = typeof model & ('Post' | 'User')
expectTypeOf<Model>().toEqualTypeOf<'Post' | 'User'>()

fnModel({ args, operation, model })

Expand Down Expand Up @@ -735,7 +740,9 @@ testMatrix.setupTestSuite(
| 'groupBy'
| 'count'
>()
expectTypeOf(model).toEqualTypeOf<'Post' | 'User'>()

type Model = typeof model & ('Post' | 'User')
expectTypeOf<Model>().toEqualTypeOf<'Post' | 'User'>()

fnModel({ args, operation, model })

Expand Down

0 comments on commit c18ede7

Please sign in to comment.