Skip to content

Commit 7b453f7

Browse files
authored
fix: improve generated typing for polymorphic models (#1002)
1 parent c1da257 commit 7b453f7

File tree

15 files changed

+123
-60
lines changed

15 files changed

+123
-60
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
"test-ci": "ZENSTACK_TEST=1 pnpm -r run test --silent --forceExit",
1010
"publish-all": "pnpm --filter \"./packages/**\" -r publish --access public",
1111
"publish-preview": "pnpm --filter \"./packages/**\" -r publish --force --registry https://preview.registry.zenstack.dev/",
12-
"unpublish-preview": "pnpm --recursive --shell-mode exec -- npm unpublish -f --registry https://preview.registry.zenstack.dev/ \"\\$PNPM_PACKAGE_NAME\""
12+
"unpublish-preview": "pnpm --recursive --shell-mode exec -- npm unpublish -f --registry https://preview.registry.zenstack.dev/ \"\\$PNPM_PACKAGE_NAME\"",
13+
"publish-next": "pnpm --filter \"./packages/**\" -r publish --access public --tag next",
14+
"publish-preview-next": "pnpm --filter \"./packages/**\" -r publish --force --registry https://preview.registry.zenstack.dev/ --tag next",
15+
"unpublish-preview-next": "pnpm --recursive --shell-mode exec -- npm unpublish -f --registry https://preview.registry.zenstack.dev/ --tag next \"\\$PNPM_PACKAGE_NAME\""
1316
},
1417
"keywords": [],
1518
"author": "",

packages/runtime/src/enhancements/create-enhancement.ts

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,60 +32,64 @@ export type TransactionIsolationLevel =
3232
| 'Snapshot'
3333
| 'Serializable';
3434

35-
/**
36-
* Options for {@link createEnhancement}
37-
*/
3835
export type EnhancementOptions = {
3936
/**
40-
* Policy definition
37+
* The kinds of enhancements to apply. By default all enhancements are applied.
4138
*/
42-
policy: PolicyDef;
39+
kinds?: EnhancementKind[];
4340

4441
/**
45-
* Model metadata
42+
* Whether to log Prisma query
4643
*/
47-
modelMeta: ModelMeta;
44+
logPrismaQuery?: boolean;
4845

4946
/**
50-
* Zod schemas for validation
47+
* Hook for transforming errors before they are thrown to the caller.
5148
*/
52-
zodSchemas?: ZodSchemas;
49+
errorTransformer?: ErrorTransformer;
5350

5451
/**
55-
* Whether to log Prisma query
52+
* The `maxWait` option passed to `prisma.$transaction()` call for transactions initiated by ZenStack.
5653
*/
57-
logPrismaQuery?: boolean;
54+
transactionMaxWait?: number;
5855

5956
/**
60-
* The Node module that contains PrismaClient
57+
* The `timeout` option passed to `prisma.$transaction()` call for transactions initiated by ZenStack.
6158
*/
62-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
63-
prismaModule: any;
59+
transactionTimeout?: number;
6460

6561
/**
66-
* The kinds of enhancements to apply. By default all enhancements are applied.
62+
* The `isolationLevel` option passed to `prisma.$transaction()` call for transactions initiated by ZenStack.
6763
*/
68-
kinds?: EnhancementKind[];
64+
transactionIsolationLevel?: TransactionIsolationLevel;
65+
};
6966

67+
/**
68+
* Options for {@link createEnhancement}
69+
*
70+
* @private
71+
*/
72+
export type InternalEnhancementOptions = EnhancementOptions & {
7073
/**
71-
* Hook for transforming errors before they are thrown to the caller.
74+
* Policy definition
7275
*/
73-
errorTransformer?: ErrorTransformer;
76+
policy: PolicyDef;
7477

7578
/**
76-
* The `maxWait` option passed to `prisma.$transaction()` call for transactions initiated by ZenStack.
79+
* Model metadata
7780
*/
78-
transactionMaxWait?: number;
81+
modelMeta: ModelMeta;
7982

8083
/**
81-
* The `timeout` option passed to `prisma.$transaction()` call for transactions initiated by ZenStack.
84+
* Zod schemas for validation
8285
*/
83-
transactionTimeout?: number;
86+
zodSchemas?: ZodSchemas;
8487

8588
/**
86-
* The `isolationLevel` option passed to `prisma.$transaction()` call for transactions initiated by ZenStack.
89+
* The Node module that contains PrismaClient
8790
*/
88-
transactionIsolationLevel?: TransactionIsolationLevel;
91+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
92+
prismaModule: any;
8993
};
9094

9195
/**
@@ -103,13 +107,15 @@ let hasDefaultAuth: boolean | undefined = undefined;
103107
* Gets a Prisma client enhanced with all enhancement behaviors, including access
104108
* policy, field validation, field omission and password hashing.
105109
*
110+
* @private
111+
*
106112
* @param prisma The Prisma client to enhance.
107113
* @param context Context.
108114
* @param options Options.
109115
*/
110116
export function createEnhancement<DbClient extends object>(
111117
prisma: DbClient,
112-
options: EnhancementOptions,
118+
options: InternalEnhancementOptions,
113119
context?: EnhancementContext
114120
) {
115121
if (!prisma) {

packages/runtime/src/enhancements/default-auth.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import deepcopy from 'deepcopy';
55
import { FieldInfo, NestedWriteVisitor, PrismaWriteActionType, enumerate, getFields } from '../cross';
66
import { DbClientContract } from '../types';
7-
import { EnhancementContext, EnhancementOptions } from './create-enhancement';
7+
import { EnhancementContext, InternalEnhancementOptions } from './create-enhancement';
88
import { DefaultPrismaProxyHandler, PrismaProxyActions, makeProxy } from './proxy';
99

1010
/**
@@ -14,7 +14,7 @@ import { DefaultPrismaProxyHandler, PrismaProxyActions, makeProxy } from './prox
1414
*/
1515
export function withDefaultAuth<DbClient extends object>(
1616
prisma: DbClient,
17-
options: EnhancementOptions,
17+
options: InternalEnhancementOptions,
1818
context?: EnhancementContext
1919
): DbClient {
2020
return makeProxy(
@@ -31,7 +31,7 @@ class DefaultAuthHandler extends DefaultPrismaProxyHandler {
3131
constructor(
3232
prisma: DbClientContract,
3333
model: string,
34-
options: EnhancementOptions,
34+
options: InternalEnhancementOptions,
3535
private readonly context?: EnhancementContext
3636
) {
3737
super(prisma, model, options);

packages/runtime/src/enhancements/delegate.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ import {
1515
resolveField,
1616
} from '../cross';
1717
import type { CrudContract, DbClientContract } from '../types';
18-
import type { EnhancementOptions } from './create-enhancement';
18+
import type { InternalEnhancementOptions } from './create-enhancement';
1919
import { Logger } from './logger';
2020
import { DefaultPrismaProxyHandler, makeProxy } from './proxy';
2121
import { QueryUtils } from './query-utils';
2222
import { formatObject, prismaClientValidationError } from './utils';
2323

24-
export function withDelegate<DbClient extends object>(prisma: DbClient, options: EnhancementOptions): DbClient {
24+
export function withDelegate<DbClient extends object>(prisma: DbClient, options: InternalEnhancementOptions): DbClient {
2525
return makeProxy(
2626
prisma,
2727
options.modelMeta,
@@ -34,7 +34,7 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
3434
private readonly logger: Logger;
3535
private readonly queryUtils: QueryUtils;
3636

37-
constructor(prisma: DbClientContract, model: string, options: EnhancementOptions) {
37+
constructor(prisma: DbClientContract, model: string, options: InternalEnhancementOptions) {
3838
super(prisma, model, options);
3939
this.logger = new Logger(prisma);
4040
this.queryUtils = new QueryUtils(prisma, this.options);

packages/runtime/src/enhancements/omit.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
/* eslint-disable @typescript-eslint/no-unused-vars */
22
/* eslint-disable @typescript-eslint/no-explicit-any */
33

4-
import { enumerate, getModelFields, resolveField, type ModelMeta } from '../cross';
4+
import { enumerate, getModelFields, resolveField } from '../cross';
55
import { DbClientContract } from '../types';
6-
import { EnhancementOptions } from './create-enhancement';
6+
import { InternalEnhancementOptions } from './create-enhancement';
77
import { DefaultPrismaProxyHandler, makeProxy } from './proxy';
88

99
/**
1010
* Gets an enhanced Prisma client that supports `@omit` attribute.
1111
*
1212
* @private
1313
*/
14-
export function withOmit<DbClient extends object>(prisma: DbClient, options: EnhancementOptions): DbClient {
14+
export function withOmit<DbClient extends object>(prisma: DbClient, options: InternalEnhancementOptions): DbClient {
1515
return makeProxy(
1616
prisma,
1717
options.modelMeta,
@@ -21,7 +21,7 @@ export function withOmit<DbClient extends object>(prisma: DbClient, options: Enh
2121
}
2222

2323
class OmitHandler extends DefaultPrismaProxyHandler {
24-
constructor(prisma: DbClientContract, model: string, options: EnhancementOptions) {
24+
constructor(prisma: DbClientContract, model: string, options: InternalEnhancementOptions) {
2525
super(prisma, model, options);
2626
}
2727

packages/runtime/src/enhancements/password.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@
33

44
import { hash } from 'bcryptjs';
55
import { DEFAULT_PASSWORD_SALT_LENGTH } from '../constants';
6-
import { NestedWriteVisitor, type ModelMeta, type PrismaWriteActionType } from '../cross';
6+
import { NestedWriteVisitor, type PrismaWriteActionType } from '../cross';
77
import { DbClientContract } from '../types';
8-
import { EnhancementOptions } from './create-enhancement';
8+
import { InternalEnhancementOptions } from './create-enhancement';
99
import { DefaultPrismaProxyHandler, PrismaProxyActions, makeProxy } from './proxy';
1010

1111
/**
1212
* Gets an enhanced Prisma client that supports `@password` attribute.
1313
*
1414
* @private
1515
*/
16-
export function withPassword<DbClient extends object = any>(prisma: DbClient, options: EnhancementOptions): DbClient {
16+
export function withPassword<DbClient extends object = any>(
17+
prisma: DbClient,
18+
options: InternalEnhancementOptions
19+
): DbClient {
1720
return makeProxy(
1821
prisma,
1922
options.modelMeta,
@@ -23,7 +26,7 @@ export function withPassword<DbClient extends object = any>(prisma: DbClient, op
2326
}
2427

2528
class PasswordHandler extends DefaultPrismaProxyHandler {
26-
constructor(prisma: DbClientContract, model: string, options: EnhancementOptions) {
29+
constructor(prisma: DbClientContract, model: string, options: InternalEnhancementOptions) {
2730
super(prisma, model, options);
2831
}
2932

packages/runtime/src/enhancements/policy/handler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import {
1616
type FieldInfo,
1717
type ModelMeta,
1818
} from '../../cross';
19-
import { type CrudContract, type DbClientContract, PolicyOperationKind } from '../../types';
20-
import type { EnhancementContext, EnhancementOptions } from '../create-enhancement';
19+
import { PolicyOperationKind, type CrudContract, type DbClientContract } from '../../types';
20+
import type { EnhancementContext, InternalEnhancementOptions } from '../create-enhancement';
2121
import { Logger } from '../logger';
2222
import { PrismaProxyHandler } from '../proxy';
2323
import { QueryUtils } from '../query-utils';
@@ -49,7 +49,7 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
4949
constructor(
5050
private readonly prisma: DbClient,
5151
model: string,
52-
private readonly options: EnhancementOptions,
52+
private readonly options: InternalEnhancementOptions,
5353
private readonly context?: EnhancementContext
5454
) {
5555
this.logger = new Logger(prisma);

packages/runtime/src/enhancements/policy/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { getIdFields } from '../../cross';
44
import { DbClientContract } from '../../types';
55
import { hasAllFields } from '../../validation';
6-
import type { EnhancementContext, EnhancementOptions } from '../create-enhancement';
6+
import type { EnhancementContext, InternalEnhancementOptions } from '../create-enhancement';
77
import { makeProxy } from '../proxy';
88
import { PolicyProxyHandler } from './handler';
99

@@ -19,7 +19,7 @@ import { PolicyProxyHandler } from './handler';
1919
*/
2020
export function withPolicy<DbClient extends object>(
2121
prisma: DbClient,
22-
options: EnhancementOptions,
22+
options: InternalEnhancementOptions,
2323
context?: EnhancementContext
2424
): DbClient {
2525
const { modelMeta, policy } = options;

packages/runtime/src/enhancements/policy/policy-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
import { enumerate, getFields, getModelFields, resolveField, zip, type FieldInfo, type ModelMeta } from '../../cross';
2020
import { AuthUser, CrudContract, DbClientContract, PolicyOperationKind } from '../../types';
2121
import { getVersion } from '../../version';
22-
import type { EnhancementContext, EnhancementOptions } from '../create-enhancement';
22+
import type { EnhancementContext, InternalEnhancementOptions } from '../create-enhancement';
2323
import { Logger } from '../logger';
2424
import { QueryUtils } from '../query-utils';
2525
import type { InputCheckFunc, PolicyDef, ReadFieldCheckFunc, ZodSchemas } from '../types';
@@ -38,7 +38,7 @@ export class PolicyUtil extends QueryUtils {
3838

3939
constructor(
4040
private readonly db: DbClientContract,
41-
options: EnhancementOptions,
41+
options: InternalEnhancementOptions,
4242
context?: EnhancementContext,
4343
private readonly shouldLogQuery = false
4444
) {

packages/runtime/src/enhancements/proxy.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { PRISMA_PROXY_ENHANCER } from '../constants';
44
import type { ModelMeta } from '../cross';
55
import type { DbClientContract } from '../types';
6-
import { EnhancementOptions } from './create-enhancement';
6+
import { InternalEnhancementOptions } from './create-enhancement';
77
import { createDeferredPromise } from './policy/promise';
88

99
/**
@@ -67,7 +67,7 @@ export class DefaultPrismaProxyHandler implements PrismaProxyHandler {
6767
constructor(
6868
protected readonly prisma: DbClientContract,
6969
protected readonly model: string,
70-
protected readonly options: EnhancementOptions
70+
protected readonly options: InternalEnhancementOptions
7171
) {}
7272

7373
async findUnique(args: any): Promise<unknown> {
@@ -241,7 +241,7 @@ export function makeProxy<T extends PrismaProxyHandler>(
241241
return propVal;
242242
}
243243

244-
return createHandlerProxy(makeHandler(target, prop), propVal, errorTransformer);
244+
return createHandlerProxy(makeHandler(target, prop), propVal, prop, errorTransformer);
245245
},
246246
});
247247

@@ -252,6 +252,7 @@ export function makeProxy<T extends PrismaProxyHandler>(
252252
function createHandlerProxy<T extends PrismaProxyHandler>(
253253
handler: T,
254254
origTarget: any,
255+
model: string,
255256
errorTransformer?: ErrorTransformer
256257
): T {
257258
return new Proxy(handler, {
@@ -282,7 +283,7 @@ function createHandlerProxy<T extends PrismaProxyHandler>(
282283
if (capture.stack && err instanceof Error) {
283284
// save the original stack and replace it with a clean one
284285
(err as any).internalStack = err.stack;
285-
err.stack = cleanCallStack(capture.stack, propKey.toString(), err.message);
286+
err.stack = cleanCallStack(capture.stack, model, propKey.toString(), err.message);
286287
}
287288

288289
if (errorTransformer) {
@@ -308,9 +309,9 @@ function createHandlerProxy<T extends PrismaProxyHandler>(
308309
}
309310

310311
// Filter out @zenstackhq/runtime stack (generated by proxy) from stack trace
311-
function cleanCallStack(stack: string, method: string, message: string) {
312+
function cleanCallStack(stack: string, model: string, method: string, message: string) {
312313
// message line
313-
let resultStack = `Error calling enhanced Prisma method \`${method}\`: ${message}`;
314+
let resultStack = `Error calling enhanced Prisma method \`${model}.${method}\`: ${message}`;
314315

315316
const lines = stack.split('\n');
316317
let foundMarker = false;

packages/runtime/src/enhancements/query-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import {
99
} from '../cross';
1010
import { CrudContract, DbClientContract } from '../types';
1111
import { getVersion } from '../version';
12-
import { EnhancementOptions } from './create-enhancement';
12+
import { InternalEnhancementOptions } from './create-enhancement';
1313
import { prismaClientUnknownRequestError, prismaClientValidationError } from './utils';
1414

1515
export class QueryUtils {
16-
constructor(private readonly prisma: DbClientContract, private readonly options: EnhancementOptions) {}
16+
constructor(private readonly prisma: DbClientContract, private readonly options: InternalEnhancementOptions) {}
1717

1818
getIdFields(model: string) {
1919
return getIdFields(this.options.modelMeta, model, true);

0 commit comments

Comments
 (0)