Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use engine implementation of findFirstOrThrow / findUniqueOrThrow #16162

Merged
merged 12 commits into from
Nov 10, 2022

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Binary file not shown.
Binary file not shown.
Binary file not shown.
36 changes: 4 additions & 32 deletions packages/client/src/generation/TSClient/Args.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import indent from 'indent-string'

import { ClientModelAction } from '../../runtime/clientActions'
import { DMMF } from '../../runtime/dmmf-types'
import { lowerCase } from '../../runtime/utils/common'
import { GenericArgsInfo } from '../GenericsArgsInfo'
Expand All @@ -16,7 +15,7 @@ export class ArgsType implements Generatable {
protected readonly args: DMMF.SchemaArg[],
protected readonly type: DMMF.OutputType,
protected readonly genericsInfo: GenericArgsInfo,
protected readonly action?: ClientModelAction,
protected readonly action?: DMMF.ModelAction,
) {}
public toTS(): string {
const { action, args } = this
Expand Down Expand Up @@ -76,8 +75,6 @@ export class ArgsType implements Generatable {
const modelArgName = getModelArgName(name, action)
if (action === DMMF.ModelAction.findUnique || action === DMMF.ModelAction.findFirst) {
return this.generateFindMethodArgs(action, name, argsToGenerate, modelArgName)
} else if (action === 'findFirstOrThrow' || action === 'findUniqueOrThrow') {
return this.generateFindOrThrowMethodArgs(action, name, modelArgName)
}

return `
Expand All @@ -97,7 +94,8 @@ ${indent(argsToGenerate.map((arg) => new InputField(arg, false, false, this.gene
modelArgName: string,
) {
const baseTypeName = getBaseTypeName(name, action)
const replacement = action === DMMF.ModelAction.findFirst ? 'findFirstOrThrow' : 'findUniqueOrThrow'
const replacement =
action === DMMF.ModelAction.findFirst ? DMMF.ModelAction.findFirstOrThrow : DMMF.ModelAction.findUniqueOrThrow

// we have to use interface for arg type here, since as for TS 4.7.2
// using BaseType & { rejectOnNotFound } intersection breaks type checking for `select`
Expand Down Expand Up @@ -125,26 +123,6 @@ export interface ${modelArgName}${ifExtensions(
}
`
}

private generateFindOrThrowMethodArgs(
action: 'findFirstOrThrow' | 'findUniqueOrThrow',
name: string,
modelArgName: string,
) {
// here we are assuming that base type have been already generated by corresponding
// DMMF actions. At the moment orThrow methods do not have any extra arguments, so arg
// type is just an alias for a base type
const baseTypeName = getBaseTypeName(name, action)
return `
/**
* ${name}: ${action}
*/
export type ${modelArgName}${ifExtensions(
'<ExtArgs extends runtime.Types.Extensions.Args = never>',
'',
)} = ${baseTypeName}${ifExtensions('<ExtArgs>', '')}
`
}
}

export class MinimalArgsType implements Generatable {
Expand Down Expand Up @@ -182,19 +160,13 @@ ${indent(
}
}

type ActionWithBaseType =
| DMMF.ModelAction.findFirst
| DMMF.ModelAction.findUnique
| 'findFirstOrThrow'
| 'findUniqueOrThrow'
type ActionWithBaseType = DMMF.ModelAction.findFirst | DMMF.ModelAction.findUnique

function getBaseTypeName(modelName: string, action: ActionWithBaseType): string {
switch (action) {
case DMMF.ModelAction.findFirst:
case 'findFirstOrThrow':
return `${modelName}FindFirstArgsBase`
case DMMF.ModelAction.findUnique:
case 'findUniqueOrThrow':
return `${modelName}FindUniqueArgsBase`
}
}
29 changes: 8 additions & 21 deletions packages/client/src/generation/TSClient/Model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ import type { GeneratorConfig } from '@prisma/generator-helper'
import indent from 'indent-string'
import { klona } from 'klona'

import {
type ClientModelAction,
allClientModelActions,
clientOnlyActions,
getDmmfActionName,
} from '../../runtime/clientActions'
import type { DMMFHelper } from '../../runtime/dmmf'
import { DMMF } from '../../runtime/dmmf-types'
import { lowerCase } from '../../runtime/utils/common'
Expand Down Expand Up @@ -65,8 +59,8 @@ export class Model implements Generatable {
}
protected get argsTypes(): Generatable[] {
const argsTypes: Generatable[] = []
for (const action of allClientModelActions) {
const fieldName = this.rootFieldNameForAction(action)
for (const action of Object.keys(DMMF.ModelAction)) {
const fieldName = this.rootFieldNameForAction(action as DMMF.ModelAction)
if (!fieldName) {
continue
}
Expand All @@ -80,7 +74,7 @@ export class Model implements Generatable {
} else if (action === 'findRaw' || action === 'aggregateRaw') {
argsTypes.push(new MinimalArgsType(field.args, this.type, this.genericsInfo, action as DMMF.ModelAction))
} else if (action !== 'groupBy' && action !== 'aggregate') {
argsTypes.push(new ArgsType(field.args, this.type, this.genericsInfo, action as ClientModelAction))
argsTypes.push(new ArgsType(field.args, this.type, this.genericsInfo, action as DMMF.ModelAction))
}
}

Expand All @@ -89,8 +83,8 @@ export class Model implements Generatable {
return argsTypes
}

private rootFieldNameForAction(action: ClientModelAction) {
return this.mapping?.[getDmmfActionName(action)]
private rootFieldNameForAction(action: DMMF.ModelAction) {
return this.mapping?.[action]
}

private getGroupByTypes() {
Expand Down Expand Up @@ -375,16 +369,9 @@ export class ModelDelegate implements Generatable {
* @param availableActions
* @returns
*/
private getNonAggregateActions(availableActions: ClientModelAction[]): ClientModelAction[] {
const actions = availableActions.filter(
(key) => key !== 'aggregate' && key !== 'groupBy' && key !== 'count',
) as ClientModelAction[]

for (const [clientOnlyAction, { wrappedAction }] of Object.entries(clientOnlyActions)) {
if (actions.includes(wrappedAction as DMMF.ModelAction)) {
actions.push(clientOnlyAction as ClientModelAction)
}
}
private getNonAggregateActions(availableActions: DMMF.ModelAction[]): DMMF.ModelAction[] {
const actions = availableActions.filter((key) => key !== 'aggregate' && key !== 'groupBy' && key !== 'count')

return actions
}

Expand Down
15 changes: 7 additions & 8 deletions packages/client/src/generation/TSClient/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import pluralize from 'pluralize'

import { ClientModelAction } from '../../runtime/clientActions'
import { DMMF } from '../../runtime/dmmf-types'
import { capitalize, lowerCase } from '../../runtime/utils/common'
import { getAggregateArgsName, getModelArgName, unique } from '../utils'
import type { JSDocMethodBodyCtx } from './jsdoc'
import { JSDocs } from './jsdoc'
import { ifExtensions } from './utils/ifExtensions'

export function getMethodJSDocBody(action: ClientModelAction, mapping: DMMF.ModelMapping, model: DMMF.Model): string {
export function getMethodJSDocBody(action: DMMF.ModelAction, mapping: DMMF.ModelMapping, model: DMMF.Model): string {
const ctx: JSDocMethodBodyCtx = {
singular: capitalize(mapping.model),
plural: capitalize(mapping.plural),
Expand All @@ -23,10 +22,10 @@ export function getMethodJSDocBody(action: ClientModelAction, mapping: DMMF.Mode
return jsdoc ? jsdoc : ''
}

export function getMethodJSDoc(action: ClientModelAction, mapping: DMMF.ModelMapping, model: DMMF.Model): string {
export function getMethodJSDoc(action: DMMF.ModelAction, mapping: DMMF.ModelMapping, model: DMMF.Model): string {
return wrapComment(getMethodJSDocBody(action, mapping, model))
}
export function getGenericMethod(name: string, actionName: ClientModelAction) {
export function getGenericMethod(name: string, actionName: DMMF.ModelAction) {
if (actionName === 'count') {
return ''
}
Expand All @@ -49,7 +48,7 @@ export function getGenericMethod(name: string, actionName: ClientModelAction) {
}
return `<T extends ${modelArgName}${ifExtensions('<ExtArgs>', '')}>`
}
export function getArgs(modelName: string, actionName: ClientModelAction) {
export function getArgs(modelName: string, actionName: DMMF.ModelAction) {
if (actionName === 'count') {
return `args?: Omit<${getModelArgName(modelName, DMMF.ModelAction.findMany)}, 'select' | 'include'>`
}
Expand All @@ -64,8 +63,8 @@ export function getArgs(modelName: string, actionName: ClientModelAction) {
actionName === DMMF.ModelAction.findFirst ||
actionName === DMMF.ModelAction.deleteMany ||
actionName === DMMF.ModelAction.createMany ||
actionName === 'findFirstOrThrow' ||
actionName === 'findUniqueOrThrow'
actionName === DMMF.ModelAction.findUniqueOrThrow ||
actionName === DMMF.ModelAction.findFirstOrThrow
? '?'
: ''
}: SelectSubset<T, ${getModelArgName(modelName, actionName)}${ifExtensions('<ExtArgs>', '')}>`
Expand All @@ -78,7 +77,7 @@ export function wrapComment(str: string): string {
}
export function getArgFieldJSDoc(
type?: DMMF.OutputType,
action?: ClientModelAction,
action?: DMMF.ModelAction,
field?: DMMF.SchemaArg | string,
): string | undefined {
if (!field || !action || !type) return
Expand Down
9 changes: 4 additions & 5 deletions packages/client/src/generation/TSClient/jsdoc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { DMMF } from '@prisma/generator-helper'

import { ClientModelAction } from '../../runtime/clientActions'
import { capitalize, lowerCase } from '../../runtime/utils/common'
import { getGroupByArgsName, getModelArgName } from '../utils'

Expand All @@ -10,7 +9,7 @@ export interface JSDocMethodBodyCtx {
firstScalar: DMMF.Field | undefined
method: string
model: DMMF.Model
action: ClientModelAction
action: DMMF.ModelAction
mapping: DMMF.ModelMapping
}

Expand All @@ -23,7 +22,7 @@ const Docs = {
}

type JSDocsType = {
[action in ClientModelAction]: {
[action in DMMF.ModelAction]: {
body: (ctx: JSDocMethodBodyCtx) => string
fields: {
[field: string]: (singular: string, plural: string) => string
Expand Down Expand Up @@ -124,8 +123,8 @@ const ${lowerCase(ctx.mapping.model)} = await ${ctx.method}({
},
findUniqueOrThrow: {
body: (ctx) =>
`Find one ${ctx.singular} that matches the filter or throw
\`NotFoundError\` if no matches were found.
`Find one ${ctx.singular} that matches the filter or throw an error with \`error.code='P2025'\`
if no matches were found.
@param {${getModelArgName(ctx.model.name, ctx.action)}} args - Arguments to find a ${ctx.singular}
@example
// Get one ${ctx.singular}
Expand Down
13 changes: 6 additions & 7 deletions packages/client/src/generation/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { assertNever } from '@prisma/internals'
import indent from 'indent-string'
import path from 'path'

import { ClientModelAction } from '../runtime/clientActions'
import type { DMMFHelper } from '../runtime/dmmf'
import { DMMF } from '../runtime/dmmf-types'
import { GraphQLScalarToJSTypeTable } from '../runtime/utils/common'
Expand Down Expand Up @@ -107,7 +106,7 @@ export function getArgName(name: string, findMany: boolean): string {

// we need names for all top level args,
// as GraphQL doesn't have the concept of unnamed args
export function getModelArgName(modelName: string, action?: ClientModelAction): string {
export function getModelArgName(modelName: string, action?: DMMF.ModelAction): string {
if (!action) {
return `${modelName}Args`
}
Expand All @@ -116,8 +115,12 @@ export function getModelArgName(modelName: string, action?: ClientModelAction):
return `${modelName}FindManyArgs`
case DMMF.ModelAction.findUnique:
return `${modelName}FindUniqueArgs`
case DMMF.ModelAction.findUniqueOrThrow:
return `${modelName}FindUniqueOrThrowArgs`
case DMMF.ModelAction.findFirst:
return `${modelName}FindFirstArgs`
case DMMF.ModelAction.findFirstOrThrow:
return `${modelName}FindFirstOrThrowArgs`
case DMMF.ModelAction.upsert:
return `${modelName}UpsertArgs`
case DMMF.ModelAction.update:
Expand All @@ -142,10 +145,6 @@ export function getModelArgName(modelName: string, action?: ClientModelAction):
return `${modelName}FindRawArgs`
case DMMF.ModelAction.aggregateRaw:
return `${modelName}AggregateRawArgs`
case 'findFirstOrThrow':
return `${modelName}FindFirstOrThrowArgs`
case 'findUniqueOrThrow':
return `${modelName}FindUniqueOrThrowArgs`
default:
assertNever(action, 'Unknown action')
}
Expand Down Expand Up @@ -213,7 +212,7 @@ export function getFieldType(field: DMMF.SchemaField): string {

interface SelectReturnTypeOptions {
name: string
actionName: ClientModelAction
actionName: DMMF.ModelAction
renderPromise?: boolean
hideCondition?: boolean
isField?: boolean
Expand Down
8 changes: 6 additions & 2 deletions packages/client/src/runtime/RequestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ import type { Document } from './query'
import { Args, unpack } from './query'
import { CallSite } from './utils/CallSite'
import { createErrorMessageWithContext } from './utils/createErrorMessageWithContext'
import type { RejectOnNotFound } from './utils/rejectOnNotFound'
import { throwIfNotFound } from './utils/rejectOnNotFound'
import { NotFoundError, RejectOnNotFound, throwIfNotFound } from './utils/rejectOnNotFound'

const debug = Debug('prisma:client:request_handler')

Expand Down Expand Up @@ -189,6 +188,11 @@ export class RequestHandler {

handleRequestError({ error, clientMethod, callsite }: HandleErrorParams): never {
debug(error)
// TODO: This is a workaround to keep backwards compatibility with clients
// consuming NotFoundError
if (error instanceof NotFoundError) {
millsp marked this conversation as resolved.
Show resolved Hide resolved
throw error
}

let message = error.message
if (callsite) {
Expand Down
33 changes: 0 additions & 33 deletions packages/client/src/runtime/clientActions.ts

This file was deleted.

This file was deleted.