diff --git a/packages/plugins/swr/tests/swr.test.ts b/packages/plugins/swr/tests/swr.test.ts index 0ae8f4f10..95e0aecfb 100644 --- a/packages/plugins/swr/tests/swr.test.ts +++ b/packages/plugins/swr/tests/swr.test.ts @@ -50,10 +50,11 @@ plugin swr { ${sharedModel} `, - true, - false, - [`${origDir}/dist`, 'react', '@types/react', 'swr'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, 'react', '@types/react', 'swr'], + compile: true, + } ); }); }); diff --git a/packages/plugins/tanstack-query/tests/plugin.test.ts b/packages/plugins/tanstack-query/tests/plugin.test.ts index 03798ea08..62d605f74 100644 --- a/packages/plugins/tanstack-query/tests/plugin.test.ts +++ b/packages/plugins/tanstack-query/tests/plugin.test.ts @@ -51,10 +51,16 @@ plugin tanstack { ${sharedModel} `, - true, - false, - [`${origDir}/dist`, 'react@18.2.0', '@types/react@18.2.0', '@tanstack/react-query@4.29.7'], - true + { + pushDb: false, + extraDependencies: [ + `${origDir}/dist`, + 'react@18.2.0', + '@types/react@18.2.0', + '@tanstack/react-query@4.29.7', + ], + compile: true, + } ); }); @@ -69,10 +75,11 @@ plugin tanstack { ${sharedModel} `, - true, - false, - [`${origDir}/dist`, 'svelte@^3.0.0', '@tanstack/svelte-query@4.29.7'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, 'svelte@^3.0.0', '@tanstack/svelte-query@4.29.7'], + compile: true, + } ); }); }); diff --git a/packages/plugins/trpc/tests/trpc.test.ts b/packages/plugins/trpc/tests/trpc.test.ts index 16e907ee7..617bbe66c 100644 --- a/packages/plugins/trpc/tests/trpc.test.ts +++ b/packages/plugins/trpc/tests/trpc.test.ts @@ -48,10 +48,12 @@ model Foo { @@ignore } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + } ); }); @@ -88,10 +90,12 @@ model Foo { @@ignore } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + } ); expect(fs.existsSync(path.join(projectDir, 'trpc'))).toBe(true); }); @@ -116,11 +120,13 @@ model Post { authorId String? } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true, - 'zenstack/schema.zmodel' + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + customSchemaFilePath: 'zenstack/schema.zmodel', + } ); expect(fs.existsSync(path.join(projectDir, 'zenstack/trpc'))).toBe(true); }); @@ -139,11 +145,13 @@ model Post { title String } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true, - 'zenstack/schema.zmodel' + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + customSchemaFilePath: 'zenstack/schema.zmodel', + } ); const content = fs.readFileSync(path.join(projectDir, 'zenstack/trpc/routers/Post.router.ts'), 'utf-8'); expect(content).toContain('findMany:'); @@ -167,11 +175,13 @@ model Post { title String } `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server'], - true, - 'zenstack/schema.zmodel' + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server'], + compile: true, + fullZod: true, + customSchemaFilePath: 'zenstack/schema.zmodel', + } ); const content = fs.readFileSync(path.join(projectDir, 'zenstack/trpc/routers/Post.router.ts'), 'utf-8'); expect(content).toContain('findMany:'); @@ -211,10 +221,12 @@ model Post { ${BLOG_BASE_SCHEMA} `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server', '@trpc/react-query'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server', '@trpc/react-query'], + compile: true, + fullZod: true, + } ); }); @@ -229,10 +241,12 @@ model Post { ${BLOG_BASE_SCHEMA} `, - true, - false, - [`${origDir}/dist`, '@trpc/client', '@trpc/server', '@trpc/next'], - true + { + pushDb: false, + extraDependencies: [`${origDir}/dist`, '@trpc/client', '@trpc/server', '@trpc/next'], + compile: true, + fullZod: true, + } ); }); }); diff --git a/packages/runtime/src/constants.ts b/packages/runtime/src/constants.ts index 1a09ac31b..d1263255f 100644 --- a/packages/runtime/src/constants.ts +++ b/packages/runtime/src/constants.ts @@ -19,11 +19,23 @@ export const GUARD_FIELD_NAME = 'zenstack_guard'; export const AUXILIARY_FIELDS = [TRANSACTION_FIELD_NAME, GUARD_FIELD_NAME]; /** - * Reasons for a CRUD operation to fail. + * Reasons for a CRUD operation to fail */ export enum CrudFailureReason { /** * CRUD suceeded but the result was not readable. */ RESULT_NOT_READABLE = 'RESULT_NOT_READABLE', + + /** + * CRUD failed because of a data validation rule violation. + */ + DATA_VALIDATION_VIOLATION = 'DATA_VALIDATION_VIOLATION', +} + +/** + * Prisma error codes used + */ +export enum PrismaErrorCode { + CONSTRAINED_FAILED = 'P2004', } diff --git a/packages/runtime/src/enhancements/policy/policy-utils.ts b/packages/runtime/src/enhancements/policy/policy-utils.ts index d7b592233..5dadf1590 100644 --- a/packages/runtime/src/enhancements/policy/policy-utils.ts +++ b/packages/runtime/src/enhancements/policy/policy-utils.ts @@ -6,7 +6,14 @@ import { lowerCaseFirst } from 'lower-case-first'; import pluralize from 'pluralize'; import { upperCaseFirst } from 'upper-case-first'; import { fromZodError } from 'zod-validation-error'; -import { AUXILIARY_FIELDS, CrudFailureReason, GUARD_FIELD_NAME, TRANSACTION_FIELD_NAME } from '../../constants'; +import { + AUXILIARY_FIELDS, + CrudFailureReason, + GUARD_FIELD_NAME, + PrismaErrorCode, + TRANSACTION_FIELD_NAME, +} from '../../constants'; +import { isPrismaClientKnownRequestError } from '../../error'; import { AuthUser, DbClientContract, @@ -402,7 +409,26 @@ export class PolicyUtil { // `Validating read of to-one relation: ${fieldInfo.type}#${formatObject(ids)}` // ); // } - await this.checkPolicyForFilter(fieldInfo.type, ids, operation, this.db); + try { + await this.checkPolicyForFilter(fieldInfo.type, ids, operation, this.db); + } catch (err) { + if ( + isPrismaClientKnownRequestError(err) && + err.code === PrismaErrorCode.CONSTRAINED_FAILED + ) { + // denied by policy + if (fieldInfo.isOptional) { + // if the relation is optional, just nullify it + entityData[field] = null; + } else { + // otherwise reject + throw err; + } + } else { + // unknown error + throw err; + } + } } } @@ -772,7 +798,7 @@ export class PolicyUtil { return prismaClientKnownRequestError( this.db, `denied by policy: ${model} entities failed '${operation}' check${extra ? ', ' + extra : ''}`, - { clientVersion: getVersion(), code: 'P2004', meta: { reason } } + { clientVersion: getVersion(), code: PrismaErrorCode.CONSTRAINED_FAILED, meta: { reason } } ); } @@ -864,7 +890,12 @@ export class PolicyUtil { if (this.logger.enabled('info')) { this.logger.info(`entity ${model} failed schema check for operation ${operation}: ${error}`); } - throw this.deniedByPolicy(model, operation, `entities failed schema check: [${error}]`); + throw this.deniedByPolicy( + model, + operation, + `entities failed schema check: [${error}]`, + CrudFailureReason.DATA_VALIDATION_VIOLATION + ); } } else { // count entities with policy injected and see if any of them are filtered out diff --git a/packages/schema/src/cli/plugin-runner.ts b/packages/schema/src/cli/plugin-runner.ts index bcaf75c95..96819cdfb 100644 --- a/packages/schema/src/cli/plugin-runner.ts +++ b/packages/schema/src/cli/plugin-runner.ts @@ -99,24 +99,35 @@ export class PluginRunner { } // make sure prerequisites are included - const corePlugins = ['@core/prisma', '@core/model-meta', '@core/access-policy']; + const corePlugins: Array<{ provider: string; options?: Record }> = [ + { provider: '@core/prisma' }, + { provider: '@core/model-meta' }, + { provider: '@core/access-policy' }, + ]; if (getDataModels(context.schema).some((model) => hasValidationAttributes(model))) { // '@core/zod' plugin is auto-enabled if there're validation rules - corePlugins.push('@core/zod'); + corePlugins.push({ provider: '@core/zod', options: { modelOnly: true } }); } - // core dependencies introduced by dependencies + // core plugins introduced by dependencies plugins .flatMap((p) => p.dependencies) .forEach((dep) => { - if (dep.startsWith('@core/') && !corePlugins.includes(dep)) { - corePlugins.push(dep); + if (dep.startsWith('@core/')) { + const existing = corePlugins.find((p) => p.provider === dep); + if (existing) { + // reset options to default + existing.options = undefined; + } else { + // add core dependency + corePlugins.push({ provider: dep }); + } } }); for (const corePlugin of corePlugins.reverse()) { - const existingIdx = plugins.findIndex((p) => p.provider === corePlugin); + const existingIdx = plugins.findIndex((p) => p.provider === corePlugin.provider); if (existingIdx >= 0) { // shift the plugin to the front const existing = plugins[existingIdx]; @@ -124,13 +135,13 @@ export class PluginRunner { plugins.unshift(existing); } else { // synthesize a plugin and insert front - const pluginModule = require(this.getPluginModulePath(corePlugin)); - const pluginName = this.getPluginName(pluginModule, corePlugin); + const pluginModule = require(this.getPluginModulePath(corePlugin.provider)); + const pluginName = this.getPluginName(pluginModule, corePlugin.provider); plugins.unshift({ name: pluginName, - provider: corePlugin, + provider: corePlugin.provider, dependencies: [], - options: { schemaPath: context.schemaPath, name: pluginName }, + options: { schemaPath: context.schemaPath, name: pluginName, ...corePlugin.options }, run: pluginModule.default, module: pluginModule, }); @@ -154,7 +165,9 @@ export class PluginRunner { let dmmf: DMMF.Document | undefined = undefined; for (const { name, provider, run, options } of plugins) { + // const start = Date.now(); await this.runPlugin(name, run, context, options, dmmf, warnings); + // console.log(`✅ Plugin ${colors.bold(name)} (${provider}) completed in ${Date.now() - start}ms`); if (provider === '@core/prisma') { // load prisma DMMF dmmf = await getDMMF({ diff --git a/packages/schema/src/plugins/prisma/schema-generator.ts b/packages/schema/src/plugins/prisma/schema-generator.ts index ecb507351..c3f899219 100644 --- a/packages/schema/src/plugins/prisma/schema-generator.ts +++ b/packages/schema/src/plugins/prisma/schema-generator.ts @@ -23,6 +23,7 @@ import { import { analyzePolicies, getDataModels, + getDMMF, getLiteral, getLiteralArray, getPrismaVersion, @@ -32,7 +33,6 @@ import { resolved, resolvePath, TRANSACTION_FIELD_NAME, - getDMMF } from '@zenstackhq/sdk'; import fs from 'fs'; import { writeFile } from 'fs/promises'; diff --git a/packages/schema/src/plugins/zod/generator.ts b/packages/schema/src/plugins/zod/generator.ts index 5b9e10521..5b9838b52 100644 --- a/packages/schema/src/plugins/zod/generator.ts +++ b/packages/schema/src/plugins/zod/generator.ts @@ -14,11 +14,7 @@ import { saveProject, } from '@zenstackhq/sdk'; import { DataModel, DataSource, EnumField, Model, isDataModel, isDataSource, isEnum } from '@zenstackhq/sdk/ast'; -import { - AggregateOperationSupport, - addMissingInputObjectTypes, - resolveAggregateOperationSupport, -} from '@zenstackhq/sdk/dmmf-helpers'; +import { addMissingInputObjectTypes, resolveAggregateOperationSupport } from '@zenstackhq/sdk/dmmf-helpers'; import { promises as fs } from 'fs'; import { streamAllContents } from 'langium'; import path from 'path'; @@ -52,8 +48,10 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF. const project = createProject(); + // common schemas await generateCommonSchemas(project, output); + // enums await generateEnumSchemas( prismaClientDmmf.schema.enumTypes.prisma, prismaClientDmmf.schema.enumTypes.model ?? [], @@ -67,15 +65,34 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF. dataSource?.fields.find((f) => f.name === 'provider')?.value ) as ConnectorType; - Transformer.provider = dataSourceProvider; - - addMissingInputObjectTypes(inputObjectTypes, outputObjectTypes, models); - - const aggregateOperationSupport = resolveAggregateOperationSupport(inputObjectTypes); + await generateModelSchemas(project, model, output); + + if (options.modelOnly !== true) { + // detailed object schemas referenced from input schemas + Transformer.provider = dataSourceProvider; + addMissingInputObjectTypes(inputObjectTypes, outputObjectTypes, models); + const aggregateOperationSupport = resolveAggregateOperationSupport(inputObjectTypes); + await generateObjectSchemas(inputObjectTypes, project, output, model); + + // input schemas + const transformer = new Transformer({ + models, + modelOperations, + aggregateOperationSupport, + project, + zmodel: model, + }); + await transformer.generateInputSchemas(); + } - await generateObjectSchemas(inputObjectTypes, project, output, model); - await generateModelSchemas(models, modelOperations, aggregateOperationSupport, project, model, output); + // create barrel file + const exports = [`export * as models from './models'`, `export * as enums from './enums'`]; + if (options.modelOnly !== true) { + exports.push(`export * as input from './input'`, `export * as objects from './objects'`); + } + project.createSourceFile(path.join(output, 'index.ts'), exports.join(';\n'), { overwrite: true }); + // emit const shouldCompile = options.compile !== false; if (!shouldCompile || options.preserveTsFiles === true) { // save ts files @@ -157,23 +174,7 @@ async function generateObjectSchemas( ); } -async function generateModelSchemas( - models: DMMF.Model[], - modelOperations: DMMF.ModelMapping[], - aggregateOperationSupport: AggregateOperationSupport, - project: Project, - zmodel: Model, - output: string -) { - const transformer = new Transformer({ - models, - modelOperations, - aggregateOperationSupport, - project, - zmodel, - }); - await transformer.generateInputSchemas(); - +async function generateModelSchemas(project: Project, zmodel: Model, output: string) { const schemaNames: string[] = []; for (const dm of getDataModels(zmodel)) { schemaNames.push(await generateModelSchema(dm, project, output)); @@ -184,16 +185,6 @@ async function generateModelSchemas( schemaNames.map((name) => `export * from './${name}';`).join('\n'), { overwrite: true } ); - - project.createSourceFile( - path.join(output, 'index.ts'), - `export * as input from './input'; - export * as models from './models'; - export * as objects from './objects'; - export * as enums from './enums'; - `, - { overwrite: true } - ); } async function generateModelSchema(model: DataModel, project: Project, output: string) { diff --git a/packages/server/src/api/rest/index.ts b/packages/server/src/api/rest/index.ts index 765f93159..4297cc6dd 100644 --- a/packages/server/src/api/rest/index.ts +++ b/packages/server/src/api/rest/index.ts @@ -3,6 +3,7 @@ import type { ModelMeta, ZodSchemas } from '@zenstackhq/runtime'; import { DbClientContract, FieldInfo, + PrismaErrorCode, enumerate, getIdFields, isPrismaClientKnownRequestError, @@ -1556,7 +1557,7 @@ class RequestHandler extends APIHandlerBase { private handlePrismaError(err: unknown) { if (isPrismaClientKnownRequestError(err)) { - if (err.code === 'P2004') { + if (err.code === PrismaErrorCode.CONSTRAINED_FAILED) { return this.makeError('forbidden', undefined, 403, err.meta?.reason as string); } else if (err.code === 'P2025' || err.code === 'P2018') { return this.makeError('notFound'); diff --git a/packages/server/src/api/rpc/index.ts b/packages/server/src/api/rpc/index.ts index e03815376..57a9437ef 100644 --- a/packages/server/src/api/rpc/index.ts +++ b/packages/server/src/api/rpc/index.ts @@ -1,5 +1,6 @@ import { DbOperations, + PrismaErrorCode, ZodSchemas, isPrismaClientKnownRequestError, isPrismaClientUnknownRequestError, @@ -148,7 +149,7 @@ class RequestHandler extends APIHandlerBase { } catch (err) { if (isPrismaClientKnownRequestError(err)) { logError(logger, err.code, err.message); - if (err.code === 'P2004') { + if (err.code === PrismaErrorCode.CONSTRAINED_FAILED) { // rejected by policy return { status: 403, diff --git a/packages/server/tests/api/rpc.test.ts b/packages/server/tests/api/rpc.test.ts index 21f22042e..f9ff2155a 100644 --- a/packages/server/tests/api/rpc.test.ts +++ b/packages/server/tests/api/rpc.test.ts @@ -13,7 +13,7 @@ describe('RPC API Handler Tests', () => { let zodSchemas: any; beforeAll(async () => { - const params = await loadSchema(schema); + const params = await loadSchema(schema, { fullZod: true }); prisma = params.prisma; zodSchemas = params.zodSchemas; }); diff --git a/packages/testtools/src/schema.ts b/packages/testtools/src/schema.ts index 5945e48d0..49a53bb5e 100644 --- a/packages/testtools/src/schema.ts +++ b/packages/testtools/src/schema.ts @@ -39,12 +39,14 @@ export type WeakDbClientContract = Record & { }; export function run(cmd: string, env?: Record, cwd?: string) { + const start = Date.now(); execSync(cmd, { stdio: 'pipe', encoding: 'utf-8', env: { ...process.env, DO_NOT_TRACK: '1', ...env }, cwd, }); + console.log('Execution took', Date.now() - start, 'ms', '-', cmd); } function normalizePath(p: string) { @@ -81,23 +83,54 @@ generator js { plugin zod { provider = '@core/zod' + modelOnly = true } `; -export async function loadSchemaFromFile(schemaFile: string, addPrelude = true, pushDb = true, logPrismaQuery = false) { +const MODEL_PRELUDE_FULL_ZOD = ` +datasource db { + provider = 'sqlite' + url = 'file:./test.db' +} + +generator js { + provider = 'prisma-client-js' + previewFeatures = ['clientExtensions'] +} + +plugin zod { + provider = '@core/zod' + modelOnly = false +} +`; + +export type SchemaLoadOptions = { + addPrelude?: boolean; + pushDb?: boolean; + fullZod?: boolean; + extraDependencies?: string[]; + compile?: boolean; + customSchemaFilePath?: string; + logPrismaQuery?: boolean; +}; + +const defaultOptions: SchemaLoadOptions = { + addPrelude: true, + pushDb: true, + fullZod: false, + extraDependencies: [], + compile: false, + logPrismaQuery: false, +}; + +export async function loadSchemaFromFile(schemaFile: string, options?: SchemaLoadOptions) { const content = fs.readFileSync(schemaFile, { encoding: 'utf-8' }); - return loadSchema(content, addPrelude, pushDb, [], false, undefined, logPrismaQuery); + return loadSchema(content, options); } -export async function loadSchema( - schema: string, - addPrelude = true, - pushDb = true, - extraDependencies: string[] = [], - compile = false, - customSchemaFilePath?: string, - logPrismaQuery = false -) { +export async function loadSchema(schema: string, options?: SchemaLoadOptions) { + const opt = { ...defaultOptions, ...options }; + const { name: projectRoot } = tmp.dirSync({ unsafeCleanup: true }); const root = getWorkspaceRoot(__dirname); @@ -129,9 +162,9 @@ export async function loadSchema( if (index === 0) { // The first file is the main schema file zmodelPath = path.join(projectRoot, fileName); - if (addPrelude) { + if (opt.addPrelude) { // plugin need to be added after import statement - fileContent = `${fileContent}\n${MODEL_PRELUDE}`; + fileContent = `${fileContent}\n${opt.fullZod ? MODEL_PRELUDE_FULL_ZOD : MODEL_PRELUDE}`; } } @@ -141,9 +174,9 @@ export async function loadSchema( }); } else { schema = schema.replaceAll('$projectRoot', projectRoot); - const content = addPrelude ? `${MODEL_PRELUDE}\n${schema}` : schema; - if (customSchemaFilePath) { - zmodelPath = path.join(projectRoot, customSchemaFilePath); + const content = opt.addPrelude ? `${opt.fullZod ? MODEL_PRELUDE_FULL_ZOD : MODEL_PRELUDE}\n${schema}` : schema; + if (opt.customSchemaFilePath) { + zmodelPath = path.join(projectRoot, opt.customSchemaFilePath); fs.mkdirSync(path.dirname(zmodelPath), { recursive: true }); fs.writeFileSync(zmodelPath, content); } else { @@ -153,7 +186,7 @@ export async function loadSchema( run('npm install'); - if (customSchemaFilePath) { + if (opt.customSchemaFilePath) { run(`npx zenstack generate --schema ${zmodelPath} --no-dependency-check`, { NODE_PATH: './node_modules', }); @@ -161,19 +194,19 @@ export async function loadSchema( run('npx zenstack generate --no-dependency-check', { NODE_PATH: './node_modules' }); } - if (pushDb) { + if (opt.pushDb) { run('npx prisma db push'); } const PrismaClient = require(path.join(projectRoot, 'node_modules/.prisma/client')).PrismaClient; const prisma = new PrismaClient({ log: ['info', 'warn', 'error'] }); - extraDependencies.forEach((dep) => { + opt.extraDependencies?.forEach((dep) => { console.log(`Installing dependency ${dep}`); run(`npm install ${dep}`); }); - if (compile) { + if (opt.compile) { console.log('Compiling...'); run('npx tsc --init'); @@ -213,11 +246,19 @@ export async function loadSchema( projectDir: projectRoot, prisma, withPolicy: (user?: AuthUser) => - withPolicy(prisma, { user }, { policy, modelMeta, zodSchemas, logPrismaQuery }), + withPolicy( + prisma, + { user }, + { policy, modelMeta, zodSchemas, logPrismaQuery: opt.logPrismaQuery } + ), withOmit: () => withOmit(prisma, { modelMeta }), withPassword: () => withPassword(prisma, { modelMeta }), withPresets: (user?: AuthUser) => - withPresets(prisma, { user }, { policy, modelMeta, zodSchemas, logPrismaQuery }), + withPresets( + prisma, + { user }, + { policy, modelMeta, zodSchemas, logPrismaQuery: opt.logPrismaQuery } + ), policy, modelMeta, zodSchemas, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 769f0daf0..058d0f821 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,7 +121,7 @@ importers: version: 0.2.1 ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5) + version: 29.0.5(@babel/core@7.22.5)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5) typescript: specifier: ^4.9.5 version: 4.9.5 @@ -192,7 +192,7 @@ importers: version: 2.0.3(react@18.2.0) ts-jest: specifier: ^29.0.5 - version: 29.0.5(@babel/core@7.22.5)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4) + version: 29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4) typescript: specifier: ^4.9.4 version: 4.9.4 @@ -10600,7 +10600,7 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-jest@29.0.5(@babel/core@7.22.5)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.4): + /ts-jest@29.0.5(@babel/core@7.22.5)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5): resolution: {integrity: sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} hasBin: true @@ -10631,7 +10631,7 @@ packages: lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.5.3 - typescript: 4.9.4 + typescript: 4.9.5 yargs-parser: 21.1.1 dev: true @@ -10670,41 +10670,6 @@ packages: yargs-parser: 21.1.1 dev: true - /ts-jest@29.0.5(@babel/core@7.22.9)(esbuild@0.18.13)(jest@29.5.0)(typescript@4.9.5): - resolution: {integrity: sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 - esbuild: '*' - jest: ^29.0.0 - typescript: '>=4.3' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - dependencies: - '@babel/core': 7.22.9 - bs-logger: 0.2.6 - esbuild: 0.18.13 - fast-json-stable-stringify: 2.1.0 - jest: 29.5.0(@types/node@18.0.0) - jest-util: 29.5.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.5.3 - typescript: 4.9.5 - yargs-parser: 21.1.1 - dev: true - /ts-morph@16.0.0: resolution: {integrity: sha512-jGNF0GVpFj0orFw55LTsQxVYEUOCWBAbR5Ls7fTYE5pQsbW18ssTb/6UXx/GYAEjS+DQTp8VoTw0vqYMiaaQuw==} dependencies: diff --git a/tests/integration/tests/e2e/todo-presets.test.ts b/tests/integration/tests/e2e/todo-presets.test.ts index 26b9afb73..28f8bd4e6 100644 --- a/tests/integration/tests/e2e/todo-presets.test.ts +++ b/tests/integration/tests/e2e/todo-presets.test.ts @@ -10,7 +10,7 @@ describe('Todo Presets Tests', () => { beforeAll(async () => { const { withPresets, prisma: _prisma } = await loadSchemaFromFile( path.join(__dirname, '../schema/todo.zmodel'), - false + { addPrelude: false } ); getDb = withPresets; prisma = _prisma; diff --git a/tests/integration/tests/with-omit/with-omit.test.ts b/tests/integration/tests/enhancements/with-omit/with-omit.test.ts similarity index 100% rename from tests/integration/tests/with-omit/with-omit.test.ts rename to tests/integration/tests/enhancements/with-omit/with-omit.test.ts diff --git a/tests/integration/tests/with-password/with-password.test.ts b/tests/integration/tests/enhancements/with-password/with-password.test.ts similarity index 100% rename from tests/integration/tests/with-password/with-password.test.ts rename to tests/integration/tests/enhancements/with-password/with-password.test.ts diff --git a/tests/integration/tests/with-policy/auth.test.ts b/tests/integration/tests/enhancements/with-policy/auth.test.ts similarity index 100% rename from tests/integration/tests/with-policy/auth.test.ts rename to tests/integration/tests/enhancements/with-policy/auth.test.ts diff --git a/tests/integration/tests/with-policy/cal-com-sample.test.ts b/tests/integration/tests/enhancements/with-policy/cal-com-sample.test.ts similarity index 54% rename from tests/integration/tests/with-policy/cal-com-sample.test.ts rename to tests/integration/tests/enhancements/with-policy/cal-com-sample.test.ts index 2aa94e4c9..4ebc7f448 100644 --- a/tests/integration/tests/with-policy/cal-com-sample.test.ts +++ b/tests/integration/tests/enhancements/with-policy/cal-com-sample.test.ts @@ -3,6 +3,9 @@ import path from 'path'; describe('Cal.com Sample Integration Tests', () => { it('model loading', async () => { - await loadSchemaFromFile(path.join(__dirname, '../schema/cal-com.zmodel'), false, false); + await loadSchemaFromFile(path.join(__dirname, '../../schema/cal-com.zmodel'), { + addPrelude: false, + pushDb: false, + }); }); }); diff --git a/tests/integration/tests/with-policy/connect-disconnect.test.ts b/tests/integration/tests/enhancements/with-policy/connect-disconnect.test.ts similarity index 100% rename from tests/integration/tests/with-policy/connect-disconnect.test.ts rename to tests/integration/tests/enhancements/with-policy/connect-disconnect.test.ts diff --git a/tests/integration/tests/with-policy/deep-nested.test.ts b/tests/integration/tests/enhancements/with-policy/deep-nested.test.ts similarity index 93% rename from tests/integration/tests/with-policy/deep-nested.test.ts rename to tests/integration/tests/enhancements/with-policy/deep-nested.test.ts index 86ac0b5a2..4b8013ecb 100644 --- a/tests/integration/tests/with-policy/deep-nested.test.ts +++ b/tests/integration/tests/enhancements/with-policy/deep-nested.test.ts @@ -204,22 +204,21 @@ describe('With Policy:deep nested', () => { }); expect(r1.m2.m4).toHaveLength(1); - // create read-back rejection: M3 @@deny('read', value == 200) - await expect( - db.m1.create({ - include: { m2: { include: { m3: true } } }, - data: { - m2: { - create: { - value: 1, - m3: { - create: { value: 200 }, - }, + // create read-back filtering: M3 @@deny('read', value == 200) + const r2 = await db.m1.create({ + include: { m2: { include: { m3: true } } }, + data: { + m2: { + create: { + value: 1, + m3: { + create: { value: 200 }, }, }, }, - }) - ).toBeRejectedByPolicy(); + }, + }); + expect(r2.m2.m3).toBeNull(); }); it('update', async () => { @@ -364,21 +363,20 @@ describe('With Policy:deep nested', () => { expect(r1.m2.m4).not.toContain(expect.objectContaining({ id: 'm4-1' })); // update read-back rejection: M3 @@deny('read', value == 200) - await expect( - db.m1.update({ - where: { myId: '1' }, - include: { m2: { include: { m3: true } } }, - data: { - m2: { - update: { - m3: { - update: { value: 200 }, - }, + const r2 = await db.m1.update({ + where: { myId: '1' }, + include: { m2: { include: { m3: true } } }, + data: { + m2: { + update: { + m3: { + update: { value: 200 }, }, }, }, - }) - ).toBeRejectedByPolicy(); + }, + }); + expect(r2.m2.m3).toBeNull(); }); it('delete', async () => { diff --git a/tests/integration/tests/with-policy/empty-policy.test.ts b/tests/integration/tests/enhancements/with-policy/empty-policy.test.ts similarity index 100% rename from tests/integration/tests/with-policy/empty-policy.test.ts rename to tests/integration/tests/enhancements/with-policy/empty-policy.test.ts diff --git a/tests/integration/tests/with-policy/field-validation.test.ts b/tests/integration/tests/enhancements/with-policy/field-validation.test.ts similarity index 100% rename from tests/integration/tests/with-policy/field-validation.test.ts rename to tests/integration/tests/enhancements/with-policy/field-validation.test.ts diff --git a/tests/integration/tests/with-policy/multi-field-unique.test.ts b/tests/integration/tests/enhancements/with-policy/multi-field-unique.test.ts similarity index 100% rename from tests/integration/tests/with-policy/multi-field-unique.test.ts rename to tests/integration/tests/enhancements/with-policy/multi-field-unique.test.ts diff --git a/tests/integration/tests/with-policy/multi-file.test.ts b/tests/integration/tests/enhancements/with-policy/multi-file.test.ts similarity index 100% rename from tests/integration/tests/with-policy/multi-file.test.ts rename to tests/integration/tests/enhancements/with-policy/multi-file.test.ts diff --git a/tests/integration/tests/with-policy/multi-id-fields.test.ts b/tests/integration/tests/enhancements/with-policy/multi-id-fields.test.ts similarity index 95% rename from tests/integration/tests/with-policy/multi-id-fields.test.ts rename to tests/integration/tests/enhancements/with-policy/multi-id-fields.test.ts index 5d9a37eaf..7dd62364a 100644 --- a/tests/integration/tests/with-policy/multi-id-fields.test.ts +++ b/tests/integration/tests/enhancements/with-policy/multi-id-fields.test.ts @@ -52,14 +52,14 @@ describe('With Policy: multiple id fields', () => { db.a.create({ data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 1 } } } }) ).toBeRejectedByPolicy(); - await expect( - db.a.create({ - include: { b: true }, - data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, - }) - ).toBeRejectedByPolicy(); - const r = await prisma.b.findUnique({ where: { b1_b2: { b1: '1', b2: '2' } } }); - expect(r.value).toBe(2); + const r = await db.a.create({ + include: { b: true }, + data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, + }); + expect(r.b).toBeNull(); + + const r1 = await prisma.b.findUnique({ where: { b1_b2: { b1: '1', b2: '2' } } }); + expect(r1.value).toBe(2); await expect( db.a.create({ diff --git a/tests/integration/tests/with-policy/nested-to-many.test.ts b/tests/integration/tests/enhancements/with-policy/nested-to-many.test.ts similarity index 86% rename from tests/integration/tests/with-policy/nested-to-many.test.ts rename to tests/integration/tests/enhancements/with-policy/nested-to-many.test.ts index c213065ed..75a8d0278 100644 --- a/tests/integration/tests/with-policy/nested-to-many.test.ts +++ b/tests/integration/tests/enhancements/with-policy/nested-to-many.test.ts @@ -12,6 +12,55 @@ describe('With Policy:nested to-many', () => { process.chdir(origDir); }); + it('read filtering', async () => { + const { withPolicy } = await loadSchema( + ` + model M1 { + id String @id @default(uuid()) + m2 M2[] + + @@allow('all', true) + } + + model M2 { + id String @id @default(uuid()) + value Int + m1 M1 @relation(fields: [m1Id], references:[id]) + m1Id String + + @@allow('create', true) + @@allow('read', value > 0) + } + ` + ); + + const db = withPolicy(); + + let read = await db.m1.create({ + include: { m2: true }, + data: { + id: '1', + m2: { + create: [{ value: 0 }], + }, + }, + }); + expect(read.m2).toHaveLength(0); + read = await db.m1.findFirst({ where: { id: '1' }, include: { m2: true } }); + expect(read.m2).toHaveLength(0); + + await db.m1.create({ + data: { + id: '2', + m2: { + create: [{ value: 0 }, { value: 1 }, { value: 2 }], + }, + }, + }); + read = await db.m1.findFirst({ where: { id: '2' }, include: { m2: true } }); + expect(read.m2).toHaveLength(2); + }); + it('create simple', async () => { const { withPolicy } = await loadSchema( ` @@ -397,15 +446,14 @@ describe('With Policy:nested to-many', () => { expect(r.m2).toHaveLength(1); // read-back for to-one relation rejected - await expect( - db.m1.create({ - include: { m3: true }, - data: { - value: 2, - m3: { create: { value: 0 } }, - }, - }) - ).toBeRejectedByPolicy(); + const r1 = await db.m1.create({ + include: { m3: true }, + data: { + value: 2, + m3: { create: { value: 0 } }, + }, + }); + expect(r1.m3).toBeNull(); }); it('update with nested read', async () => { @@ -457,21 +505,20 @@ describe('With Policy:nested to-many', () => { }, }); - await expect( - db.m1.update({ - where: { id: '1' }, - include: { m3: true }, - data: { - m3: { - update: { - value: 1, - }, + const r = await db.m1.update({ + where: { id: '1' }, + include: { m3: true }, + data: { + m3: { + update: { + value: 1, }, }, - }) - ).toBeRejectedByPolicy(); + }, + }); + expect(r.m3).toBeNull(); - const r = await db.m1.update({ + const r1 = await db.m1.update({ where: { id: '1' }, include: { m3: true, m2: true }, data: { @@ -483,11 +530,11 @@ describe('With Policy:nested to-many', () => { }, }); // m3 is ok now - expect(r.m3.value).toBe(2); + expect(r1.m3.value).toBe(2); // m2 got filtered - expect(r.m2).toHaveLength(0); + expect(r1.m2).toHaveLength(0); - const r1 = await db.m1.update({ + const r2 = await db.m1.update({ where: { id: '1' }, select: { m2: true }, data: { @@ -500,6 +547,6 @@ describe('With Policy:nested to-many', () => { }, }); // one of m2 matches policy now - expect(r1.m2).toHaveLength(1); + expect(r2.m2).toHaveLength(1); }); }); diff --git a/tests/integration/tests/with-policy/nested-to-one.test.ts b/tests/integration/tests/enhancements/with-policy/nested-to-one.test.ts similarity index 71% rename from tests/integration/tests/with-policy/nested-to-one.test.ts rename to tests/integration/tests/enhancements/with-policy/nested-to-one.test.ts index b1f3b7a50..45a0e765d 100644 --- a/tests/integration/tests/with-policy/nested-to-one.test.ts +++ b/tests/integration/tests/enhancements/with-policy/nested-to-one.test.ts @@ -12,6 +12,93 @@ describe('With Policy:nested to-one', () => { process.chdir(origDir); }); + it('read fitering for optional relation', async () => { + const { prisma, withPolicy } = await loadSchema( + ` + model M1 { + id String @id @default(uuid()) + m2 M2? + + @@allow('all', true) + } + + model M2 { + id String @id @default(uuid()) + m1 M1 @relation(fields: [m1Id], references:[id]) + m1Id String @unique + value Int + + @@allow('create', true) + @@allow('read', value > 0) + } + ` + ); + + const db = withPolicy(); + + let read = await db.m1.create({ + include: { m2: true }, + data: { + id: '1', + m2: { + create: { id: '1', value: 0 }, + }, + }, + }); + expect(read.m2).toBeNull(); + + await expect(db.m1.findUnique({ where: { id: '1' }, include: { m2: true } })).resolves.toEqual( + expect.objectContaining({ m2: null }) + ); + await expect(db.m1.findMany({ include: { m2: true } })).resolves.toEqual( + expect.arrayContaining([expect.objectContaining({ m2: null })]) + ); + + await prisma.m2.update({ where: { id: '1' }, data: { value: 1 } }); + read = await db.m1.findUnique({ where: { id: '1' }, include: { m2: true } }); + expect(read.m2).toEqual(expect.objectContaining({ id: '1', value: 1 })); + }); + + it('read rejection for non-optional relation', async () => { + const { prisma, withPolicy } = await loadSchema( + ` + model M1 { + id String @id @default(uuid()) + m2 M2? + value Int + + @@allow('create', true) + @@allow('read', value > 0) + } + + model M2 { + id String @id @default(uuid()) + m1 M1 @relation(fields: [m1Id], references:[id]) + m1Id String @unique + + @@allow('all', true) + } + ` + ); + + await prisma.m1.create({ + data: { + id: '1', + value: 0, + m2: { + create: { id: '1' }, + }, + }, + }); + + const db = withPolicy(); + await expect(db.m2.findUnique({ where: { id: '1' }, include: { m1: true } })).toBeRejectedByPolicy(); + await expect(db.m2.findMany({ include: { m1: true } })).toBeRejectedByPolicy(); + + await prisma.m1.update({ where: { id: '1' }, data: { value: 1 } }); + await expect(db.m2.findMany({ include: { m1: true } })).toResolveTruthy(); + }); + it('create and update tests', async () => { const { withPolicy } = await loadSchema( ` diff --git a/tests/integration/tests/with-policy/petstore-sample.test.ts b/tests/integration/tests/enhancements/with-policy/petstore-sample.test.ts similarity index 94% rename from tests/integration/tests/with-policy/petstore-sample.test.ts rename to tests/integration/tests/enhancements/with-policy/petstore-sample.test.ts index c04615ffa..88b0b1f7d 100644 --- a/tests/integration/tests/with-policy/petstore-sample.test.ts +++ b/tests/integration/tests/enhancements/with-policy/petstore-sample.test.ts @@ -8,8 +8,8 @@ describe('Pet Store Policy Tests', () => { beforeAll(async () => { const { withPolicy, prisma: _prisma } = await loadSchemaFromFile( - path.join(__dirname, '../schema/petstore.zmodel'), - false + path.join(__dirname, '../../schema/petstore.zmodel'), + { addPrelude: false } ); getDb = withPolicy; prisma = _prisma; diff --git a/tests/integration/tests/with-policy/post-update.test.ts b/tests/integration/tests/enhancements/with-policy/post-update.test.ts similarity index 100% rename from tests/integration/tests/with-policy/post-update.test.ts rename to tests/integration/tests/enhancements/with-policy/post-update.test.ts diff --git a/tests/integration/tests/with-policy/relation-many-to-many-filter.test.ts b/tests/integration/tests/enhancements/with-policy/relation-many-to-many-filter.test.ts similarity index 100% rename from tests/integration/tests/with-policy/relation-many-to-many-filter.test.ts rename to tests/integration/tests/enhancements/with-policy/relation-many-to-many-filter.test.ts diff --git a/tests/integration/tests/with-policy/relation-one-to-many-filter.test.ts b/tests/integration/tests/enhancements/with-policy/relation-one-to-many-filter.test.ts similarity index 100% rename from tests/integration/tests/with-policy/relation-one-to-many-filter.test.ts rename to tests/integration/tests/enhancements/with-policy/relation-one-to-many-filter.test.ts diff --git a/tests/integration/tests/with-policy/relation-one-to-one-filter.test.ts b/tests/integration/tests/enhancements/with-policy/relation-one-to-one-filter.test.ts similarity index 100% rename from tests/integration/tests/with-policy/relation-one-to-one-filter.test.ts rename to tests/integration/tests/enhancements/with-policy/relation-one-to-one-filter.test.ts diff --git a/tests/integration/tests/with-policy/self-relation.test.ts b/tests/integration/tests/enhancements/with-policy/self-relation.test.ts similarity index 100% rename from tests/integration/tests/with-policy/self-relation.test.ts rename to tests/integration/tests/enhancements/with-policy/self-relation.test.ts diff --git a/tests/integration/tests/with-policy/todo-sample.test.ts b/tests/integration/tests/enhancements/with-policy/todo-sample.test.ts similarity index 99% rename from tests/integration/tests/with-policy/todo-sample.test.ts rename to tests/integration/tests/enhancements/with-policy/todo-sample.test.ts index 4b61e20a8..0f3305e0e 100644 --- a/tests/integration/tests/with-policy/todo-sample.test.ts +++ b/tests/integration/tests/enhancements/with-policy/todo-sample.test.ts @@ -8,8 +8,8 @@ describe('Todo Policy Tests', () => { beforeAll(async () => { const { withPolicy, prisma: _prisma } = await loadSchemaFromFile( - path.join(__dirname, '../schema/todo.zmodel'), - false + path.join(__dirname, '../../schema/todo.zmodel'), + { addPrelude: false } ); getDb = withPolicy; prisma = _prisma; diff --git a/tests/integration/tests/with-policy/toplevel-operations.test.ts b/tests/integration/tests/enhancements/with-policy/toplevel-operations.test.ts similarity index 100% rename from tests/integration/tests/with-policy/toplevel-operations.test.ts rename to tests/integration/tests/enhancements/with-policy/toplevel-operations.test.ts diff --git a/tests/integration/tests/with-policy/unique-as-id.test.ts b/tests/integration/tests/enhancements/with-policy/unique-as-id.test.ts similarity index 80% rename from tests/integration/tests/with-policy/unique-as-id.test.ts rename to tests/integration/tests/enhancements/with-policy/unique-as-id.test.ts index 42dd7ce05..e4d399204 100644 --- a/tests/integration/tests/with-policy/unique-as-id.test.ts +++ b/tests/integration/tests/enhancements/with-policy/unique-as-id.test.ts @@ -47,14 +47,13 @@ describe('With Policy: unique as id', () => { db.a.create({ data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 1 } } } }) ).toBeRejectedByPolicy(); - await expect( - db.a.create({ - include: { b: true }, - data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, - }) - ).toBeRejectedByPolicy(); - const r = await prisma.b.findUnique({ where: { b1: '1' } }); - expect(r.value).toBe(2); + const r = await db.a.create({ + include: { b: true }, + data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, + }); + expect(r.b).toBeNull(); + const r1 = await prisma.b.findUnique({ where: { b1: '1' } }); + expect(r1.value).toBe(2); await expect( db.a.create({ @@ -101,14 +100,13 @@ describe('With Policy: unique as id', () => { db.a.create({ data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 1 } } } }) ).toBeRejectedByPolicy(); - await expect( - db.a.create({ - include: { b: true }, - data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, - }) - ).toBeRejectedByPolicy(); - const r = await prisma.b.findUnique({ where: { b1: '1' } }); - expect(r.value).toBe(2); + const r = await db.a.create({ + include: { b: true }, + data: { x: '2', y: 3, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, + }); + expect(r.b).toBeNull(); + const r1 = await prisma.b.findUnique({ where: { b1: '1' } }); + expect(r1.value).toBe(2); await expect( db.a.create({ @@ -158,14 +156,13 @@ describe('With Policy: unique as id', () => { db.a.create({ data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 1 } } } }) ).toBeRejectedByPolicy(); - await expect( - db.a.create({ - include: { b: true }, - data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, - }) - ).toBeRejectedByPolicy(); - const r = await prisma.b.findUnique({ where: { b1_b2: { b1: '1', b2: '2' } } }); - expect(r.value).toBe(2); + const r = await db.a.create({ + include: { b: true }, + data: { x: '2', y: 1, value: 1, b: { create: { b1: '1', b2: '2', value: 2 } } }, + }); + expect(r.b).toBeNull(); + const r1 = await prisma.b.findUnique({ where: { b1_b2: { b1: '1', b2: '2' } } }); + expect(r1.value).toBe(2); await expect( db.a.create({ diff --git a/tests/integration/tests/with-policy/view.test.ts b/tests/integration/tests/enhancements/with-policy/view.test.ts similarity index 98% rename from tests/integration/tests/with-policy/view.test.ts rename to tests/integration/tests/enhancements/with-policy/view.test.ts index d0dd92c07..1af13a65c 100644 --- a/tests/integration/tests/with-policy/view.test.ts +++ b/tests/integration/tests/enhancements/with-policy/view.test.ts @@ -52,7 +52,7 @@ describe('View Policy Test', () => { @@allow('read', postCount > 1) } `, - false + { addPrelude: false } ); await prisma.$executeRaw`CREATE VIEW UserInfo as select user.id, user.name, user.email, user.id as userId, count(post.id) as postCount from user left join post on user.id = post.authorId group by user.id;`; diff --git a/tests/integration/tests/nextjs/generation.test.ts b/tests/integration/tests/frameworks/nextjs/generation.test.ts similarity index 100% rename from tests/integration/tests/nextjs/generation.test.ts rename to tests/integration/tests/frameworks/nextjs/generation.test.ts diff --git a/tests/integration/tests/nextjs/test-project/.gitignore b/tests/integration/tests/frameworks/nextjs/test-project/.gitignore similarity index 100% rename from tests/integration/tests/nextjs/test-project/.gitignore rename to tests/integration/tests/frameworks/nextjs/test-project/.gitignore diff --git a/tests/integration/tests/nextjs/test-project/.npmrc b/tests/integration/tests/frameworks/nextjs/test-project/.npmrc similarity index 100% rename from tests/integration/tests/nextjs/test-project/.npmrc rename to tests/integration/tests/frameworks/nextjs/test-project/.npmrc diff --git a/tests/integration/tests/nextjs/test-project/README.md b/tests/integration/tests/frameworks/nextjs/test-project/README.md similarity index 100% rename from tests/integration/tests/nextjs/test-project/README.md rename to tests/integration/tests/frameworks/nextjs/test-project/README.md diff --git a/tests/integration/tests/nextjs/test-project/next.config.js b/tests/integration/tests/frameworks/nextjs/test-project/next.config.js similarity index 100% rename from tests/integration/tests/nextjs/test-project/next.config.js rename to tests/integration/tests/frameworks/nextjs/test-project/next.config.js diff --git a/tests/integration/tests/nextjs/test-project/package.json b/tests/integration/tests/frameworks/nextjs/test-project/package.json similarity index 79% rename from tests/integration/tests/nextjs/test-project/package.json rename to tests/integration/tests/frameworks/nextjs/test-project/package.json index ff766686f..e8c006202 100644 --- a/tests/integration/tests/nextjs/test-project/package.json +++ b/tests/integration/tests/frameworks/nextjs/test-project/package.json @@ -13,8 +13,8 @@ "@types/node": "18.11.18", "@types/react": "18.0.27", "@types/react-dom": "18.0.10", - "@zenstackhq/runtime": "../../../../../../packages/runtime/dist", - "@zenstackhq/swr": "../../../../../../packages/plugins/swr/dist", + "@zenstackhq/runtime": "../../../../../../../packages/runtime/dist", + "@zenstackhq/swr": "../../../../../../../packages/plugins/swr/dist", "next": "13.1.4", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/tests/integration/tests/nextjs/test-project/pages/_app.tsx b/tests/integration/tests/frameworks/nextjs/test-project/pages/_app.tsx similarity index 100% rename from tests/integration/tests/nextjs/test-project/pages/_app.tsx rename to tests/integration/tests/frameworks/nextjs/test-project/pages/_app.tsx diff --git a/tests/integration/tests/nextjs/test-project/pages/api/model/[...path].ts b/tests/integration/tests/frameworks/nextjs/test-project/pages/api/model/[...path].ts similarity index 100% rename from tests/integration/tests/nextjs/test-project/pages/api/model/[...path].ts rename to tests/integration/tests/frameworks/nextjs/test-project/pages/api/model/[...path].ts diff --git a/tests/integration/tests/nextjs/test-project/pages/index.tsx b/tests/integration/tests/frameworks/nextjs/test-project/pages/index.tsx similarity index 100% rename from tests/integration/tests/nextjs/test-project/pages/index.tsx rename to tests/integration/tests/frameworks/nextjs/test-project/pages/index.tsx diff --git a/tests/integration/tests/nextjs/test-project/postgres.zmodel b/tests/integration/tests/frameworks/nextjs/test-project/postgres.zmodel similarity index 100% rename from tests/integration/tests/nextjs/test-project/postgres.zmodel rename to tests/integration/tests/frameworks/nextjs/test-project/postgres.zmodel diff --git a/tests/integration/tests/nextjs/test-project/server/db.ts b/tests/integration/tests/frameworks/nextjs/test-project/server/db.ts similarity index 100% rename from tests/integration/tests/nextjs/test-project/server/db.ts rename to tests/integration/tests/frameworks/nextjs/test-project/server/db.ts diff --git a/tests/integration/tests/nextjs/test-project/sqlite.zmodel b/tests/integration/tests/frameworks/nextjs/test-project/sqlite.zmodel similarity index 100% rename from tests/integration/tests/nextjs/test-project/sqlite.zmodel rename to tests/integration/tests/frameworks/nextjs/test-project/sqlite.zmodel diff --git a/tests/integration/tests/nextjs/test-project/tsconfig.json b/tests/integration/tests/frameworks/nextjs/test-project/tsconfig.json similarity index 100% rename from tests/integration/tests/nextjs/test-project/tsconfig.json rename to tests/integration/tests/frameworks/nextjs/test-project/tsconfig.json diff --git a/tests/integration/tests/trpc/generation.test.ts b/tests/integration/tests/frameworks/trpc/generation.test.ts similarity index 100% rename from tests/integration/tests/trpc/generation.test.ts rename to tests/integration/tests/frameworks/trpc/generation.test.ts diff --git a/tests/integration/tests/trpc/test-project/.gitignore b/tests/integration/tests/frameworks/trpc/test-project/.gitignore similarity index 100% rename from tests/integration/tests/trpc/test-project/.gitignore rename to tests/integration/tests/frameworks/trpc/test-project/.gitignore diff --git a/tests/integration/tests/trpc/test-project/.npmrc b/tests/integration/tests/frameworks/trpc/test-project/.npmrc similarity index 100% rename from tests/integration/tests/trpc/test-project/.npmrc rename to tests/integration/tests/frameworks/trpc/test-project/.npmrc diff --git a/tests/integration/tests/trpc/test-project/README.md b/tests/integration/tests/frameworks/trpc/test-project/README.md similarity index 100% rename from tests/integration/tests/trpc/test-project/README.md rename to tests/integration/tests/frameworks/trpc/test-project/README.md diff --git a/tests/integration/tests/trpc/test-project/lib/trpc.ts b/tests/integration/tests/frameworks/trpc/test-project/lib/trpc.ts similarity index 100% rename from tests/integration/tests/trpc/test-project/lib/trpc.ts rename to tests/integration/tests/frameworks/trpc/test-project/lib/trpc.ts diff --git a/tests/integration/tests/trpc/test-project/next.config.js b/tests/integration/tests/frameworks/trpc/test-project/next.config.js similarity index 100% rename from tests/integration/tests/trpc/test-project/next.config.js rename to tests/integration/tests/frameworks/trpc/test-project/next.config.js diff --git a/tests/integration/tests/trpc/test-project/package.json b/tests/integration/tests/frameworks/trpc/test-project/package.json similarity index 77% rename from tests/integration/tests/trpc/test-project/package.json rename to tests/integration/tests/frameworks/trpc/test-project/package.json index c1962d8f2..7bb67cbff 100644 --- a/tests/integration/tests/trpc/test-project/package.json +++ b/tests/integration/tests/frameworks/trpc/test-project/package.json @@ -24,11 +24,11 @@ "superjson": "^1.12.2", "typescript": "4.9.4", "zod": "3.21.1", - "@zenstackhq/runtime": "../../../../../../packages/runtime/dist" + "@zenstackhq/runtime": "../../../../../../../packages/runtime/dist" }, "devDependencies": { "prisma": "^4.0.0", - "zenstack": "../../../../../../packages/schema/dist", - "@zenstackhq/trpc": "../../../../../../packages/plugins/trpc/dist" + "zenstack": "../../../../../../../packages/schema/dist", + "@zenstackhq/trpc": "../../../../../../../packages/plugins/trpc/dist" } } diff --git a/tests/integration/tests/trpc/test-project/pages/_app.tsx b/tests/integration/tests/frameworks/trpc/test-project/pages/_app.tsx similarity index 100% rename from tests/integration/tests/trpc/test-project/pages/_app.tsx rename to tests/integration/tests/frameworks/trpc/test-project/pages/_app.tsx diff --git a/tests/integration/tests/trpc/test-project/pages/api/model/[...path].ts b/tests/integration/tests/frameworks/trpc/test-project/pages/api/model/[...path].ts similarity index 100% rename from tests/integration/tests/trpc/test-project/pages/api/model/[...path].ts rename to tests/integration/tests/frameworks/trpc/test-project/pages/api/model/[...path].ts diff --git a/tests/integration/tests/trpc/test-project/pages/index.tsx b/tests/integration/tests/frameworks/trpc/test-project/pages/index.tsx similarity index 100% rename from tests/integration/tests/trpc/test-project/pages/index.tsx rename to tests/integration/tests/frameworks/trpc/test-project/pages/index.tsx diff --git a/tests/integration/tests/trpc/test-project/server/context.ts b/tests/integration/tests/frameworks/trpc/test-project/server/context.ts similarity index 100% rename from tests/integration/tests/trpc/test-project/server/context.ts rename to tests/integration/tests/frameworks/trpc/test-project/server/context.ts diff --git a/tests/integration/tests/trpc/test-project/server/db.ts b/tests/integration/tests/frameworks/trpc/test-project/server/db.ts similarity index 100% rename from tests/integration/tests/trpc/test-project/server/db.ts rename to tests/integration/tests/frameworks/trpc/test-project/server/db.ts diff --git a/tests/integration/tests/trpc/test-project/server/routers/_app.ts b/tests/integration/tests/frameworks/trpc/test-project/server/routers/_app.ts similarity index 100% rename from tests/integration/tests/trpc/test-project/server/routers/_app.ts rename to tests/integration/tests/frameworks/trpc/test-project/server/routers/_app.ts diff --git a/tests/integration/tests/trpc/test-project/todo.zmodel b/tests/integration/tests/frameworks/trpc/test-project/todo.zmodel similarity index 100% rename from tests/integration/tests/trpc/test-project/todo.zmodel rename to tests/integration/tests/frameworks/trpc/test-project/todo.zmodel diff --git a/tests/integration/tests/trpc/test-project/tsconfig.json b/tests/integration/tests/frameworks/trpc/test-project/tsconfig.json similarity index 100% rename from tests/integration/tests/trpc/test-project/tsconfig.json rename to tests/integration/tests/frameworks/trpc/test-project/tsconfig.json diff --git a/tests/integration/tests/plugins/prisma.test.ts b/tests/integration/tests/plugins/prisma.test.ts index 34809634b..9e462f578 100644 --- a/tests/integration/tests/plugins/prisma.test.ts +++ b/tests/integration/tests/plugins/prisma.test.ts @@ -35,7 +35,7 @@ plugin prisma { output = './db/schema.prisma' } `; - const { projectDir } = await loadSchema(model, true, false); + const { projectDir } = await loadSchema(model, { pushDb: false }); expect(fs.existsSync(path.join(projectDir, './db/schema.prisma'))).toEqual(true); }); @@ -53,7 +53,7 @@ plugin prisma { output = '${outDir}/db/schema.prisma' } `; - await loadSchema(model, true, false); + await loadSchema(model, { pushDb: false }); expect(fs.existsSync(path.join(outDir, './db/schema.prisma'))).toEqual(true); }); }); diff --git a/tests/integration/tests/plugins/zod.test.ts b/tests/integration/tests/plugins/zod.test.ts index 5fb335143..136155aaf 100644 --- a/tests/integration/tests/plugins/zod.test.ts +++ b/tests/integration/tests/plugins/zod.test.ts @@ -52,7 +52,7 @@ describe('Zod plugin tests', () => { } `; - const { zodSchemas } = await loadSchema(model, false, false); + const { zodSchemas } = await loadSchema(model, { addPrelude: false, pushDb: false }); const schemas = zodSchemas.models; expect(schemas.UserSchema).toBeTruthy(); expect(schemas.UserCreateSchema).toBeTruthy(); @@ -141,7 +141,7 @@ describe('Zod plugin tests', () => { } `; - const { zodSchemas } = await loadSchema(model, false, false); + const { zodSchemas } = await loadSchema(model, { addPrelude: false, pushDb: false }); const schema = zodSchemas.models.MCreateSchema; @@ -234,7 +234,7 @@ describe('Zod plugin tests', () => { } `; - const { zodSchemas } = await loadSchema(model, false, false); + const { zodSchemas } = await loadSchema(model, { addPrelude: false, pushDb: false }); const schema = zodSchemas.models.MCreateSchema; expect(schema.safeParse({ email: 'abd@x.com', x: 0 }).error.toString()).toMatch(/condition1/); @@ -285,7 +285,7 @@ describe('Zod plugin tests', () => { } `; - const { zodSchemas } = await loadSchema(model, false, false); + const { zodSchemas } = await loadSchema(model, { addPrelude: false, pushDb: false }); const schema = zodSchemas.models.MCreateSchema; expect(schema.safeParse({}).error.toString()).toMatch(/condition1/);