diff --git a/packages/plugins/openapi/src/rpc-generator.ts b/packages/plugins/openapi/src/rpc-generator.ts index cb388aae2..9e20df4ad 100644 --- a/packages/plugins/openapi/src/rpc-generator.ts +++ b/packages/plugins/openapi/src/rpc-generator.ts @@ -1,22 +1,22 @@ // Inspired by: https://github.com/omar-dulaimi/prisma-trpc-generator -import { analyzePolicies, PluginError, requireOption, resolvePath } from '@zenstackhq/sdk'; +import { PluginError, analyzePolicies, requireOption, resolvePath, supportCreateMany } from '@zenstackhq/sdk'; import { DataModel, isDataModel } from '@zenstackhq/sdk/ast'; import { + AggregateOperationSupport, addMissingInputObjectTypesForAggregate, addMissingInputObjectTypesForInclude, addMissingInputObjectTypesForModelArgs, addMissingInputObjectTypesForSelect, - AggregateOperationSupport, resolveAggregateOperationSupport, } from '@zenstackhq/sdk/dmmf-helpers'; -import type { DMMF } from '@zenstackhq/sdk/prisma'; +import { type DMMF } from '@zenstackhq/sdk/prisma'; import * as fs from 'fs'; import { lowerCaseFirst } from 'lower-case-first'; import type { OpenAPIV3_1 as OAPI } from 'openapi-types'; import * as path from 'path'; import invariant from 'tiny-invariant'; -import { match, P } from 'ts-pattern'; +import { P, match } from 'ts-pattern'; import { upperCaseFirst } from 'upper-case-first'; import YAML from 'yaml'; import { name } from '.'; @@ -166,7 +166,7 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { }); } - if (ops['createMany']) { + if (ops['createMany'] && supportCreateMany(zmodel.$container)) { definitions.push({ method: 'post', operation: 'createMany', @@ -704,7 +704,7 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { private generateEnumComponent(_enum: DMMF.SchemaEnum): OAPI.SchemaObject { const schema: OAPI.SchemaObject = { type: 'string', - enum: _enum.values, + enum: _enum.values as string[], }; return schema; } @@ -793,17 +793,14 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { return result; } - private setInputRequired(fields: { name: string; isRequired: boolean }[], result: OAPI.NonArraySchemaObject) { + private setInputRequired(fields: readonly DMMF.SchemaArg[], result: OAPI.NonArraySchemaObject) { const required = fields.filter((f) => f.isRequired).map((f) => f.name); if (required.length > 0) { result.required = required; } } - private setOutputRequired( - fields: { name: string; isNullable?: boolean; outputType: DMMF.OutputTypeRef }[], - result: OAPI.NonArraySchemaObject - ) { + private setOutputRequired(fields: readonly DMMF.SchemaField[], result: OAPI.NonArraySchemaObject) { const required = fields.filter((f) => f.isNullable !== true).map((f) => f.name); if (required.length > 0) { result.required = required; diff --git a/packages/plugins/swr/src/generator.ts b/packages/plugins/swr/src/generator.ts index 182b9786c..a785ed8f4 100644 --- a/packages/plugins/swr/src/generator.ts +++ b/packages/plugins/swr/src/generator.ts @@ -8,6 +8,7 @@ import { requireOption, resolvePath, saveProject, + supportCreateMany, } from '@zenstackhq/sdk'; import { DataModel, DataModelFieldType, Model, isEnum } from '@zenstackhq/sdk/ast'; import { getPrismaClientImportSpec, type DMMF } from '@zenstackhq/sdk/prisma'; @@ -85,7 +86,7 @@ function generateModelHooks( } // createMany - if (mapping.createMany) { + if (mapping.createMany && supportCreateMany(model.$container)) { const argsType = `Prisma.${model.name}CreateManyArgs`; mutationFuncs.push(generateMutation(sf, model, 'POST', 'createMany', argsType, true)); } diff --git a/packages/plugins/tanstack-query/src/generator.ts b/packages/plugins/tanstack-query/src/generator.ts index 8709f1a7e..db7b30e83 100644 --- a/packages/plugins/tanstack-query/src/generator.ts +++ b/packages/plugins/tanstack-query/src/generator.ts @@ -9,6 +9,7 @@ import { requireOption, resolvePath, saveProject, + supportCreateMany, } from '@zenstackhq/sdk'; import { DataModel, DataModelFieldType, Model, isEnum } from '@zenstackhq/sdk/ast'; import { getPrismaClientImportSpec, type DMMF } from '@zenstackhq/sdk/prisma'; @@ -348,7 +349,7 @@ function generateModelHooks( } // createMany - if (mapping.createMany) { + if (mapping.createMany && supportCreateMany(model.$container)) { generateMutationHook(target, sf, model.name, 'createMany', 'post', false, 'Prisma.BatchPayload'); } diff --git a/packages/plugins/trpc/src/generator.ts b/packages/plugins/trpc/src/generator.ts index 46d30a37d..01b1ca2f7 100644 --- a/packages/plugins/trpc/src/generator.ts +++ b/packages/plugins/trpc/src/generator.ts @@ -7,6 +7,7 @@ import { requireOption, resolvePath, saveProject, + supportCreateMany, type PluginOptions, } from '@zenstackhq/sdk'; import { Model } from '@zenstackhq/sdk/ast'; @@ -79,11 +80,11 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF. function createAppRouter( outDir: string, - modelOperations: DMMF.ModelMapping[], + modelOperations: readonly DMMF.ModelMapping[], hiddenModels: string[], generateModelActions: string[] | undefined, generateClientHelpers: string[] | undefined, - _zmodel: Model, + zmodel: Model, zodSchemasImport: string, options: PluginOptions ) { @@ -171,7 +172,8 @@ function createAppRouter( generateModelActions, generateClientHelpers, zodSchemasImport, - options + options, + zmodel ); appRouter.addImportDeclaration({ @@ -241,7 +243,8 @@ function generateModelCreateRouter( generateModelActions: string[] | undefined, generateClientHelpers: string[] | undefined, zodSchemasImport: string, - options: PluginOptions + options: PluginOptions, + zmodel: Model ) { const modelRouter = project.createSourceFile(path.resolve(outputDir, 'routers', `${model}.router.ts`), undefined, { overwrite: true, @@ -298,6 +301,10 @@ function generateModelCreateRouter( inputType && (!generateModelActions || generateModelActions.includes(generateOpName)) ) { + if (generateOpName === 'createMany' && !supportCreateMany(zmodel)) { + continue; + } + generateProcedure(funcWriter, generateOpName, upperCaseFirst(inputType), model, baseOpType); if (routerTypingStructure) { diff --git a/packages/plugins/trpc/src/helpers.ts b/packages/plugins/trpc/src/helpers.ts index 947b96b98..726d31263 100644 --- a/packages/plugins/trpc/src/helpers.ts +++ b/packages/plugins/trpc/src/helpers.ts @@ -327,7 +327,7 @@ export const getProcedureTypeByOpName = (opName: string) => { return procType; }; -export function resolveModelsComments(models: DMMF.Model[], hiddenModels: string[]) { +export function resolveModelsComments(models: readonly DMMF.Model[], hiddenModels: string[]) { const modelAttributeRegex = /(@@Gen\.)+([A-z])+(\()+(.+)+(\))+/; const attributeNameRegex = /(?:\.)+([A-Za-z])+(?:\()+/; const attributeArgsRegex = /(?:\()+([A-Za-z])+:+(.+)+(?:\))+/; diff --git a/packages/runtime/src/enhancements/policy/policy-utils.ts b/packages/runtime/src/enhancements/policy/policy-utils.ts index d2cea30fa..f485a3a17 100644 --- a/packages/runtime/src/enhancements/policy/policy-utils.ts +++ b/packages/runtime/src/enhancements/policy/policy-utils.ts @@ -982,6 +982,11 @@ export class PolicyUtil extends QueryUtils { } private doInjectReadCheckSelect(model: string, args: any, input: any) { + // omit should be ignored to avoid interfering with field selection + if (args.omit) { + delete args.omit; + } + if (!input?.select) { return; } @@ -1178,6 +1183,12 @@ export class PolicyUtil extends QueryUtils { continue; } + if (queryArgs?.omit?.[field] === true) { + // respect `{ omit: { [field]: true } }` + delete entityData[field]; + continue; + } + if (hasFieldLevelPolicy) { // 1. remove fields selected for checking field-level policies but not selected by the original query args // 2. evaluate field-level policies and remove fields that are not readable diff --git a/packages/schema/src/plugins/enhancer/enhance/index.ts b/packages/schema/src/plugins/enhancer/enhance/index.ts index f4d2e5325..0993f323c 100644 --- a/packages/schema/src/plugins/enhancer/enhance/index.ts +++ b/packages/schema/src/plugins/enhancer/enhance/index.ts @@ -56,7 +56,7 @@ export class EnhancerGenerator { private readonly outDir: string ) {} - async generate() { + async generate(): Promise<{ dmmf: DMMF.Document | undefined }> { let logicalPrismaClientDir: string | undefined; let dmmf: DMMF.Document | undefined; diff --git a/packages/schema/src/plugins/zod/generator.ts b/packages/schema/src/plugins/zod/generator.ts index a9b963d30..a73c4c442 100644 --- a/packages/schema/src/plugins/zod/generator.ts +++ b/packages/schema/src/plugins/zod/generator.ts @@ -107,7 +107,7 @@ export class ZodSchemaGenerator { project: this.project, inputObjectTypes, }); - await transformer.generateInputSchemas(this.options); + await transformer.generateInputSchemas(this.options, this.model); this.sourceFiles.push(...transformer.sourceFiles); } @@ -189,7 +189,10 @@ export class ZodSchemaGenerator { ); } - private async generateEnumSchemas(prismaSchemaEnum: DMMF.SchemaEnum[], modelSchemaEnum: DMMF.SchemaEnum[]) { + private async generateEnumSchemas( + prismaSchemaEnum: readonly DMMF.SchemaEnum[], + modelSchemaEnum: readonly DMMF.SchemaEnum[] + ) { const enumTypes = [...prismaSchemaEnum, ...modelSchemaEnum]; const enumNames = enumTypes.map((enumItem) => upperCaseFirst(enumItem.name)); Transformer.enumNames = enumNames ?? []; diff --git a/packages/schema/src/plugins/zod/transformer.ts b/packages/schema/src/plugins/zod/transformer.ts index 4fb04cdcc..c81e17024 100644 --- a/packages/schema/src/plugins/zod/transformer.ts +++ b/packages/schema/src/plugins/zod/transformer.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ -import { indentString, type PluginOptions } from '@zenstackhq/sdk'; +import { indentString, supportCreateMany, type PluginOptions } from '@zenstackhq/sdk'; +import type { Model } from '@zenstackhq/sdk/ast'; import { checkModelHasModelRelation, findModelByName, isAggregateInputType } from '@zenstackhq/sdk/dmmf-helpers'; import { type DMMF as PrismaDMMF } from '@zenstackhq/sdk/prisma'; import path from 'path'; @@ -11,12 +12,12 @@ import { AggregateOperationSupport, TransformerParams } from './types'; export default class Transformer { name: string; originalName: string; - fields: PrismaDMMF.SchemaArg[]; + fields: readonly PrismaDMMF.SchemaArg[]; schemaImports = new Set(); - models: PrismaDMMF.Model[]; + models: readonly PrismaDMMF.Model[]; modelOperations: PrismaDMMF.ModelMapping[]; aggregateOperationSupport: AggregateOperationSupport; - enumTypes: PrismaDMMF.SchemaEnum[]; + enumTypes: readonly PrismaDMMF.SchemaEnum[]; static enumNames: string[] = []; static rawOpsMap: { [name: string]: string } = {}; @@ -389,7 +390,7 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`; return wrapped; } - async generateInputSchemas(options: PluginOptions) { + async generateInputSchemas(options: PluginOptions, zmodel: Model) { const globalExports: string[] = []; // whether Prisma's Unchecked* series of input types should be generated @@ -489,7 +490,7 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`; operations.push(['create', origModelName]); } - if (createMany) { + if (createMany && supportCreateMany(zmodel)) { imports.push( `import { ${modelName}CreateManyInputObjectSchema } from '../objects/${modelName}CreateManyInput.schema'` ); diff --git a/packages/schema/src/plugins/zod/types.ts b/packages/schema/src/plugins/zod/types.ts index b64995448..a53281437 100644 --- a/packages/schema/src/plugins/zod/types.ts +++ b/packages/schema/src/plugins/zod/types.ts @@ -2,10 +2,10 @@ import type { DMMF as PrismaDMMF } from '@zenstackhq/sdk/prisma'; import { Project } from 'ts-morph'; export type TransformerParams = { - enumTypes?: PrismaDMMF.SchemaEnum[]; - fields?: PrismaDMMF.SchemaArg[]; + enumTypes?: readonly PrismaDMMF.SchemaEnum[]; + fields?: readonly PrismaDMMF.SchemaArg[]; name?: string; - models?: PrismaDMMF.Model[]; + models?: readonly PrismaDMMF.Model[]; modelOperations?: PrismaDMMF.ModelMapping[]; aggregateOperationSupport?: AggregateOperationSupport; isDefaultPrismaClientOutput?: boolean; diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 07440c38a..e0489d48f 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -18,8 +18,8 @@ "author": "", "license": "MIT", "dependencies": { - "@prisma/generator-helper": "5.7.0", - "@prisma/internals": "5.7.0", + "@prisma/generator-helper": "^5.13.0", + "@prisma/internals": "^5.13.0", "@zenstackhq/language": "workspace:*", "@zenstackhq/runtime": "workspace:*", "langium": "1.3.1", diff --git a/packages/sdk/src/dmmf-helpers/include-helpers.ts b/packages/sdk/src/dmmf-helpers/include-helpers.ts index c09c72426..23c9a9e12 100644 --- a/packages/sdk/src/dmmf-helpers/include-helpers.ts +++ b/packages/sdk/src/dmmf-helpers/include-helpers.ts @@ -1,7 +1,10 @@ import type { DMMF } from '../prisma'; import { checkIsModelRelationField, checkModelHasManyModelRelation, checkModelHasModelRelation } from './model-helpers'; -export function addMissingInputObjectTypesForInclude(inputObjectTypes: DMMF.InputType[], models: DMMF.Model[]) { +export function addMissingInputObjectTypesForInclude( + inputObjectTypes: DMMF.InputType[], + models: readonly DMMF.Model[] +) { // generate input object types necessary to support ModelInclude with relation support const generatedIncludeInputObjectTypes = generateModelIncludeInputObjectTypes(models); @@ -9,7 +12,7 @@ export function addMissingInputObjectTypesForInclude(inputObjectTypes: DMMF.Inpu inputObjectTypes.push(includeInputObjectType); } } -function generateModelIncludeInputObjectTypes(models: DMMF.Model[]) { +function generateModelIncludeInputObjectTypes(models: readonly DMMF.Model[]) { const modelIncludeInputObjectTypes: DMMF.InputType[] = []; for (const model of models) { const { name: modelName, fields: modelFields } = model; diff --git a/packages/sdk/src/dmmf-helpers/model-helpers.ts b/packages/sdk/src/dmmf-helpers/model-helpers.ts index 62bbd9980..2528eeeed 100644 --- a/packages/sdk/src/dmmf-helpers/model-helpers.ts +++ b/packages/sdk/src/dmmf-helpers/model-helpers.ts @@ -31,6 +31,6 @@ export function checkIsManyModelRelationField(modelField: DMMF.Field) { return checkIsModelRelationField(modelField) && modelField.isList; } -export function findModelByName(models: DMMF.Model[], modelName: string) { +export function findModelByName(models: readonly DMMF.Model[], modelName: string) { return models.find(({ name }) => name === modelName); } diff --git a/packages/sdk/src/dmmf-helpers/modelArgs-helpers.ts b/packages/sdk/src/dmmf-helpers/modelArgs-helpers.ts index 79b3a9f98..fb47b0096 100644 --- a/packages/sdk/src/dmmf-helpers/modelArgs-helpers.ts +++ b/packages/sdk/src/dmmf-helpers/modelArgs-helpers.ts @@ -1,14 +1,17 @@ import type { DMMF } from '../prisma'; import { checkModelHasModelRelation } from './model-helpers'; -export function addMissingInputObjectTypesForModelArgs(inputObjectTypes: DMMF.InputType[], models: DMMF.Model[]) { +export function addMissingInputObjectTypesForModelArgs( + inputObjectTypes: DMMF.InputType[], + models: readonly DMMF.Model[] +) { const modelArgsInputObjectTypes = generateModelArgsInputObjectTypes(models); for (const modelArgsInputObjectType of modelArgsInputObjectTypes) { inputObjectTypes.push(modelArgsInputObjectType); } } -function generateModelArgsInputObjectTypes(models: DMMF.Model[]) { +function generateModelArgsInputObjectTypes(models: readonly DMMF.Model[]) { const modelArgsInputObjectTypes: DMMF.InputType[] = []; for (const model of models) { const { name: modelName } = model; diff --git a/packages/sdk/src/dmmf-helpers/select-helpers.ts b/packages/sdk/src/dmmf-helpers/select-helpers.ts index 6037eecd8..a5e3e68a1 100644 --- a/packages/sdk/src/dmmf-helpers/select-helpers.ts +++ b/packages/sdk/src/dmmf-helpers/select-helpers.ts @@ -4,7 +4,7 @@ import { checkIsModelRelationField, checkModelHasManyModelRelation } from './mod export function addMissingInputObjectTypesForSelect( inputObjectTypes: DMMF.InputType[], outputObjectTypes: DMMF.OutputType[], - models: DMMF.Model[] + models: readonly DMMF.Model[] ) { // generate input object types necessary to support ModelSelect._count const modelCountOutputTypes = getModelCountOutputTypes(outputObjectTypes); @@ -89,7 +89,7 @@ function generateModelCountOutputTypeArgsInputObjectTypes(modelCountOutputTypes: return modelCountOutputTypeArgsInputObjectTypes; } -function generateModelSelectInputObjectTypes(models: DMMF.Model[]) { +function generateModelSelectInputObjectTypes(models: readonly DMMF.Model[]) { const modelSelectInputObjectTypes: DMMF.InputType[] = []; for (const model of models) { const { name: modelName, fields: modelFields } = model; @@ -97,16 +97,9 @@ function generateModelSelectInputObjectTypes(models: DMMF.Model[]) { for (const modelField of modelFields) { const { name: modelFieldName, isList, type } = modelField; + const inputTypes = [{ isList: false, type: 'Boolean', location: 'scalar' }]; const isRelationField = checkIsModelRelationField(modelField); - - const field: DMMF.SchemaArg = { - name: modelFieldName, - isRequired: false, - isNullable: false, - inputTypes: [{ isList: false, type: 'Boolean', location: 'scalar' }], - }; - if (isRelationField) { const schemaArgInputType: DMMF.InputTypeRef = { isList: false, @@ -114,9 +107,15 @@ function generateModelSelectInputObjectTypes(models: DMMF.Model[]) { location: 'inputObjectTypes', namespace: 'prisma', }; - field.inputTypes.push(schemaArgInputType); + inputTypes.push(schemaArgInputType); } + const field: DMMF.SchemaArg = { + name: modelFieldName, + isRequired: false, + isNullable: false, + inputTypes: inputTypes as DMMF.InputTypeRef[], + }; fields.push(field); } diff --git a/packages/sdk/src/utils.ts b/packages/sdk/src/utils.ts index 1bed512c8..7510ca1cd 100644 --- a/packages/sdk/src/utils.ts +++ b/packages/sdk/src/utils.ts @@ -17,6 +17,7 @@ import { isConfigArrayExpr, isDataModel, isDataModelField, + isDataSource, isEnumField, isExpression, isGeneratorDecl, @@ -32,7 +33,9 @@ import { } from '@zenstackhq/language/ast'; import fs from 'node:fs'; import path from 'path'; +import semver from 'semver'; import { ExpressionContext, STD_LIB_MODULE_NAME } from './constants'; +import { getPrismaVersion } from './prisma'; import { PluginError, type PluginDeclaredOptions, type PluginOptions } from './types'; /** @@ -367,7 +370,7 @@ export function resolvePath(_path: string, options: Pick(options: PluginDeclaredOptions, name: string, pluginName: string): T { const value = options[name]; if (value === undefined) { - throw new PluginError(pluginName, `Plugin "${options.name}" is missing required option: ${name}`); + throw new PluginError(pluginName, `required option "${name}" is not provided`); } return value as T; } @@ -531,3 +534,28 @@ export function ensureEmptyDir(dir: string) { throw new Error(`Path "${dir}" already exists and is not a directory`); } } + +/** + * Gets the data source provider from the given model. + */ +export function getDataSourceProvider(model: Model) { + const dataSource = model.declarations.find(isDataSource); + if (!dataSource) { + return undefined; + } + const provider = dataSource?.fields.find((f) => f.name === 'provider'); + if (!provider) { + return undefined; + } + return getLiteral(provider.value); +} + +/** + * Returns if the given model supports `createMany` operation. + */ +export function supportCreateMany(model: Model) { + // `createMany` is supported for sqlite since Prisma 5.12.0 + const prismaVersion = getPrismaVersion(); + const dsProvider = getDataSourceProvider(model); + return dsProvider !== 'sqlite' || (prismaVersion && semver.gte(prismaVersion, '5.12.0')); +} diff --git a/packages/testtools/src/schema.ts b/packages/testtools/src/schema.ts index c2109e579..4495ddf14 100644 --- a/packages/testtools/src/schema.ts +++ b/packages/testtools/src/schema.ts @@ -97,6 +97,7 @@ datasource db { generator js { provider = 'prisma-client-js' + ${options.previewFeatures ? `previewFeatures = ${JSON.stringify(options.previewFeatures)}` : ''} } plugin enhancer { @@ -133,6 +134,7 @@ export type SchemaLoadOptions = { projectDir?: string; preserveTsFiles?: boolean; generatePermissionChecker?: boolean; + previewFeatures?: string[]; }; const defaultOptions: SchemaLoadOptions = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 645c1c6d6..a8e8c7318 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -621,11 +621,11 @@ importers: packages/sdk: dependencies: '@prisma/generator-helper': - specifier: 5.7.0 - version: 5.7.0 + specifier: ^5.13.0 + version: 5.13.0 '@prisma/internals': - specifier: 5.7.0 - version: 5.7.0 + specifier: ^5.13.0 + version: 5.13.0 '@zenstackhq/language': specifier: workspace:* version: link:../language/dist @@ -3877,7 +3877,6 @@ packages: /@prisma/debug@5.13.0: resolution: {integrity: sha512-699iqlEvzyCj9ETrXhs8o8wQc/eVW+FigSsHpiskSFydhjVuwTJEfj/nIYqTaWFYuxiWQRfm3r01meuW97SZaQ==} - dev: true /@prisma/debug@5.7.0: resolution: {integrity: sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA==} @@ -3885,7 +3884,6 @@ packages: /@prisma/engines-version@5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b: resolution: {integrity: sha512-AyUuhahTINGn8auyqYdmxsN+qn0mw3eg+uhkp8zwknXYIqoT3bChG4RqNY/nfDkPvzWAPBa9mrDyBeOnWSgO6A==} - dev: true /@prisma/engines-version@5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9: resolution: {integrity: sha512-V6tgRVi62jRwTm0Hglky3Scwjr/AKFBFtS+MdbsBr7UOuiu1TKLPc6xfPiyEN1+bYqjEtjxwGsHgahcJsd1rNg==} @@ -3899,7 +3897,6 @@ packages: '@prisma/engines-version': 5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b '@prisma/fetch-engine': 5.13.0 '@prisma/get-platform': 5.13.0 - dev: true /@prisma/engines@5.7.0: resolution: {integrity: sha512-TkOMgMm60n5YgEKPn9erIvFX2/QuWnl3GBo6yTRyZKk5O5KQertXiNnrYgSLy0SpsKmhovEPQb+D4l0SzyE7XA==} @@ -3917,7 +3914,6 @@ packages: '@prisma/debug': 5.13.0 '@prisma/engines-version': 5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b '@prisma/get-platform': 5.13.0 - dev: true /@prisma/fetch-engine@5.7.0: resolution: {integrity: sha512-zIn/qmO+N/3FYe7/L9o+yZseIU8ivh4NdPKSkQRIHfg2QVTVMnbhGoTcecbxfVubeTp+DjcbjS0H9fCuM4W04w==} @@ -3927,6 +3923,12 @@ packages: '@prisma/get-platform': 5.7.0 dev: false + /@prisma/generator-helper@5.13.0: + resolution: {integrity: sha512-i+53beJ0dxkDrkHdsXxmeMf+eVhyhOIpL0SdBga8vwe0qHPrAIJ/lpuT/Hj0y5awTmq40qiUEmhXwCEuM/Z17w==} + dependencies: + '@prisma/debug': 5.13.0 + dev: false + /@prisma/generator-helper@5.7.0: resolution: {integrity: sha512-Fn4hJHKGJ49+E8sxpfslRauB3Goa3RAENJ/W25NMR754B9KxvmbCJyE3MT/lIZxML2nGgIdXYUtoDHZHnRaKDw==} dependencies: @@ -3937,7 +3939,6 @@ packages: resolution: {integrity: sha512-B/WrQwYTzwr7qCLifQzYOmQhZcFmIFhR81xC45gweInSUn2hTEbfKUPd2keAog+y5WI5xLAFNJ3wkXplvSVkSw==} dependencies: '@prisma/debug': 5.13.0 - dev: true /@prisma/get-platform@5.7.0: resolution: {integrity: sha512-ZeV/Op4bZsWXuw5Tg05WwRI8BlKiRFhsixPcAM+5BKYSiUZiMKIi713tfT3drBq8+T0E1arNZgYSA9QYcglWNA==} @@ -3945,6 +3946,20 @@ packages: '@prisma/debug': 5.7.0 dev: false + /@prisma/internals@5.13.0: + resolution: {integrity: sha512-OPMzS+IBPzCLT4s+IfGUbOhGFY51CFbokIFMZuoSeLKWE8UvDlitiXZ3OlVqDPUc0AlH++ysQHzDISHbZD+ZUg==} + dependencies: + '@prisma/debug': 5.13.0 + '@prisma/engines': 5.13.0 + '@prisma/fetch-engine': 5.13.0 + '@prisma/generator-helper': 5.13.0 + '@prisma/get-platform': 5.13.0 + '@prisma/prisma-schema-wasm': 5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b + '@prisma/schema-files-loader': 5.13.0 + arg: 5.0.2 + prompts: 2.4.2 + dev: false + /@prisma/internals@5.7.0: resolution: {integrity: sha512-O9x47W1DECAyvNjYUx6oZHmTX10emKuBgsFHZemUbkIcJdCsp3X8Cy2JMJ5z3hqkRX6a6omMamFsWjuTARoaSw==} dependencies: @@ -3958,10 +3973,20 @@ packages: prompts: 2.4.2 dev: false + /@prisma/prisma-schema-wasm@5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b: + resolution: {integrity: sha512-+IhHvuE1wKlyOpJgwAhGop1oqEt+1eixrCeikBIshRhdX6LwjmtRxVxVMlP5nS1yyughmpfkysIW4jZTa+Zjuw==} + dev: false + /@prisma/prisma-schema-wasm@5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9: resolution: {integrity: sha512-w+HdQtux0dJDEn6BG3fgNn+fXErXiekj9n//uHRAgrmZghockJkhnikOmG8aSXjTb1Tu5DrGasBX+rYX6rHT1w==} dev: false + /@prisma/schema-files-loader@5.13.0: + resolution: {integrity: sha512-6sVMoqobkWKsmzb98LfLiIt/aFRucWfkzSUBsqk7sc+h99xjynJt6aKtM2SSkyndFdWpRU0OiCHfQ9UlYUEJIw==} + dependencies: + fs-extra: 11.1.1 + dev: false + /@readme/better-ajv-errors@1.6.0(ajv@8.12.0): resolution: {integrity: sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==} engines: {node: '>=14'} @@ -8501,7 +8526,6 @@ packages: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 - dev: true /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} @@ -8802,7 +8826,6 @@ packages: /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true /grapheme-splitter@1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} @@ -10160,7 +10183,6 @@ packages: universalify: 2.0.0 optionalDependencies: graceful-fs: 4.2.11 - dev: true /jsonpointer@5.0.1: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} @@ -14455,7 +14477,6 @@ packages: /universalify@2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} - dev: true /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} diff --git a/tests/integration/tests/enhancements/with-policy/prisma-omit.test.ts b/tests/integration/tests/enhancements/with-policy/prisma-omit.test.ts new file mode 100644 index 000000000..d46c31245 --- /dev/null +++ b/tests/integration/tests/enhancements/with-policy/prisma-omit.test.ts @@ -0,0 +1,57 @@ +import { loadSchema } from '@zenstackhq/testtools'; + +describe('prisma omit', () => { + it('test', async () => { + const { prisma, enhance } = await loadSchema( + ` + model User { + id String @id @default(cuid()) + name String + profile Profile? + age Int + value Int @allow('read', age > 20) + @@allow('all', age > 18) + } + + model Profile { + id String @id @default(cuid()) + user User @relation(fields: [userId], references: [id]) + userId String @unique + level Int + @@allow('all', level > 1) + } + `, + { previewFeatures: ['omitApi'], logPrismaQuery: true } + ); + + await prisma.user.create({ + data: { + name: 'John', + age: 25, + value: 10, + profile: { + create: { level: 2 }, + }, + }, + }); + + const db = enhance(); + let found = await db.user.findFirst({ + include: { profile: { omit: { level: true } } }, + omit: { + age: true, + }, + }); + expect(found.age).toBeUndefined(); + expect(found.value).toEqual(10); + expect(found.profile.level).toBeUndefined(); + + found = await db.user.findFirst({ + select: { value: true, profile: { omit: { level: true } } }, + }); + console.log(found); + expect(found.age).toBeUndefined(); + expect(found.value).toEqual(10); + expect(found.profile.level).toBeUndefined(); + }); +});