diff --git a/packages/plugins/openapi/src/rest-generator.ts b/packages/plugins/openapi/src/rest-generator.ts index 6e50126d8..a6c313f79 100644 --- a/packages/plugins/openapi/src/rest-generator.ts +++ b/packages/plugins/openapi/src/rest-generator.ts @@ -2,7 +2,6 @@ import type { DMMF } from '@prisma/generator-helper'; import { - AUXILIARY_FIELDS, analyzePolicies, getDataModels, hasAttribute, @@ -829,7 +828,7 @@ export class RESTfulOpenAPIGenerator extends OpenAPIGeneratorBase { } private generateModelEntity(model: DataModel, mode: 'read' | 'create' | 'update'): OAPI.SchemaObject { - const fields = model.fields.filter((f) => !AUXILIARY_FIELDS.includes(f.name) && !isIdField(f)); + const fields = model.fields.filter((f) => !isIdField(f)); const attributes: Record = {}; const relationships: Record = {}; diff --git a/packages/plugins/openapi/src/rpc-generator.ts b/packages/plugins/openapi/src/rpc-generator.ts index 24cb41f94..0bddd1f73 100644 --- a/packages/plugins/openapi/src/rpc-generator.ts +++ b/packages/plugins/openapi/src/rpc-generator.ts @@ -1,7 +1,7 @@ // Inspired by: https://github.com/omar-dulaimi/prisma-trpc-generator import type { DMMF } from '@prisma/generator-helper'; -import { analyzePolicies, AUXILIARY_FIELDS, PluginError, requireOption, resolvePath } from '@zenstackhq/sdk'; +import { analyzePolicies, PluginError, requireOption, resolvePath } from '@zenstackhq/sdk'; import { DataModel, isDataModel } from '@zenstackhq/sdk/ast'; import { addMissingInputObjectTypesForAggregate, @@ -681,7 +681,7 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { private generateEnumComponent(_enum: DMMF.SchemaEnum): OAPI.SchemaObject { const schema: OAPI.SchemaObject = { type: 'string', - enum: _enum.values.filter((f) => !AUXILIARY_FIELDS.includes(f)), + enum: _enum.values, }; return schema; } @@ -689,9 +689,8 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { private generateEntityComponent(model: DMMF.Model): OAPI.SchemaObject { const properties: Record = {}; - const fields = model.fields.filter((f) => !AUXILIARY_FIELDS.includes(f.name)); const required: string[] = []; - for (const field of fields) { + for (const field of model.fields) { properties[field.name] = this.generateField(field); if (field.isRequired && !(field.relationName && field.isList)) { required.push(field.name); @@ -721,8 +720,7 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { private generateInputComponent(input: DMMF.InputType): OAPI.SchemaObject { const properties: Record = {}; - const fields = input.fields.filter((f) => !AUXILIARY_FIELDS.includes(f.name)); - for (const field of fields) { + for (const field of input.fields) { const options = field.inputTypes .filter( (f) => @@ -737,14 +735,13 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { } const result: OAPI.SchemaObject = { type: 'object', properties }; - this.setInputRequired(fields, result); + this.setInputRequired(input.fields, result); return result; } private generateOutputComponent(output: DMMF.OutputType): OAPI.SchemaObject { const properties: Record = {}; - const fields = output.fields.filter((f) => !AUXILIARY_FIELDS.includes(f.name)); - for (const field of fields) { + for (const field of output.fields) { let outputType: OAPI.ReferenceObject | OAPI.SchemaObject; switch (field.outputType.location) { case 'scalar': @@ -762,7 +759,7 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase { } const result: OAPI.SchemaObject = { type: 'object', properties }; - this.setOutputRequired(fields, result); + this.setOutputRequired(output.fields, result); return result; } diff --git a/packages/runtime/src/constants.ts b/packages/runtime/src/constants.ts index 859184c3c..6006eb618 100644 --- a/packages/runtime/src/constants.ts +++ b/packages/runtime/src/constants.ts @@ -3,21 +3,6 @@ */ export const DEFAULT_PASSWORD_SALT_LENGTH = 12; -/** - * Auxiliary database field for supporting policy check for nested writes - */ -export const TRANSACTION_FIELD_NAME = 'zenstack_transaction'; - -/** - * Auxiliary database field for building up policy check queries - */ -export const GUARD_FIELD_NAME = 'zenstack_guard'; - -/** - * All Auxiliary fields. - */ -export const AUXILIARY_FIELDS = [TRANSACTION_FIELD_NAME, GUARD_FIELD_NAME]; - /** * Reasons for a CRUD operation to fail */ diff --git a/packages/runtime/src/enhancements/policy/policy-utils.ts b/packages/runtime/src/enhancements/policy/policy-utils.ts index f6e69f086..459028007 100644 --- a/packages/runtime/src/enhancements/policy/policy-utils.ts +++ b/packages/runtime/src/enhancements/policy/policy-utils.ts @@ -5,7 +5,6 @@ import { lowerCaseFirst } from 'lower-case-first'; import { upperCaseFirst } from 'upper-case-first'; import { fromZodError } from 'zod-validation-error'; import { - AUXILIARY_FIELDS, CrudFailureReason, FIELD_LEVEL_READ_CHECKER_PREFIX, FIELD_LEVEL_READ_CHECKER_SELECTOR, @@ -952,13 +951,6 @@ export class PolicyUtil { return; } - // strip auxiliary fields - for (const auxField of AUXILIARY_FIELDS) { - if (auxField in entityData) { - delete entityData[auxField]; - } - } - for (const [field, fieldData] of Object.entries(entityData)) { if (fieldData === undefined) { continue; diff --git a/packages/runtime/src/enhancements/utils.ts b/packages/runtime/src/enhancements/utils.ts index c166672b3..5032bfef9 100644 --- a/packages/runtime/src/enhancements/utils.ts +++ b/packages/runtime/src/enhancements/utils.ts @@ -3,7 +3,6 @@ import { lowerCaseFirst } from 'lower-case-first'; import path from 'path'; import * as util from 'util'; -import { AUXILIARY_FIELDS } from '../constants'; import { DbClientContract } from '../types'; import { ModelMeta } from './types'; @@ -11,7 +10,7 @@ import { ModelMeta } from './types'; * Gets field names in a data model entity, filtering out internal fields. */ export function getModelFields(data: object) { - return data ? Object.keys(data).filter((f) => !AUXILIARY_FIELDS.includes(f)) : []; + return data ? Object.keys(data) : []; } /** diff --git a/packages/schema/src/cli/config.ts b/packages/schema/src/cli/config.ts index 99aa66a2e..3a803f751 100644 --- a/packages/schema/src/cli/config.ts +++ b/packages/schema/src/cli/config.ts @@ -1,15 +1,10 @@ -import { GUARD_FIELD_NAME, TRANSACTION_FIELD_NAME } from '@zenstackhq/sdk'; import fs from 'fs'; import z, { ZodError } from 'zod'; import { fromZodError } from 'zod-validation-error'; import { CliError } from './cli-error'; -const schema = z - .object({ - guardFieldName: z.string().default(GUARD_FIELD_NAME), - transactionFieldName: z.string().default(TRANSACTION_FIELD_NAME), - }) - .strict(); +// TODO: future use +const schema = z.object({}); export type ConfigType = z.infer; diff --git a/packages/schema/src/plugins/access-policy/expression-writer.ts b/packages/schema/src/plugins/access-policy/expression-writer.ts index a2bbfe2e4..0ae94b6ae 100644 --- a/packages/schema/src/plugins/access-policy/expression-writer.ts +++ b/packages/schema/src/plugins/access-policy/expression-writer.ts @@ -559,7 +559,7 @@ export class ExpressionWriter { // TODO: do we need short-circuit for logical operators? if (operator === '&&') { - // // && short-circuit: left && right -> left ? right : { zenstack_guard: false } + // // && short-circuit: left && right -> left ? right : FALSE // if (!this.hasFieldAccess(expr.left)) { // this.plain(expr.left); // this.writer.write(' ? '); @@ -573,7 +573,7 @@ export class ExpressionWriter { }); // } } else { - // // || short-circuit: left || right -> left ? { zenstack_guard: true } : right + // // || short-circuit: left || right -> left ? TRUE : right // if (!this.hasFieldAccess(expr.left)) { // this.plain(expr.left); // this.writer.write(' ? '); diff --git a/packages/schema/src/plugins/prisma/prisma-builder.ts b/packages/schema/src/plugins/prisma/prisma-builder.ts index adea22e4b..493e7c46d 100644 --- a/packages/schema/src/plugins/prisma/prisma-builder.ts +++ b/packages/schema/src/plugins/prisma/prisma-builder.ts @@ -1,4 +1,3 @@ -import { AUXILIARY_FIELDS } from '@zenstackhq/sdk'; import indentString from './indent-string'; /** @@ -155,19 +154,16 @@ export class Model extends ContainerDeclaration { } toString(): string { - const auxiliaryFields = this.fields.filter((f) => AUXILIARY_FIELDS.includes(f.name)); // eslint-disable-next-line @typescript-eslint/no-explicit-any - const result: any[] = this.fields.filter((f) => !AUXILIARY_FIELDS.includes(f.name)); - - if (auxiliaryFields.length > 0) { - // Add a blank line before the auxiliary fields - result.push('', ...auxiliaryFields); - if (this.attributes.length > 0) { - // Add a blank line before the attributes - result.push(''); - } + const result: any[] = [...this.fields]; + + if (this.attributes.length > 0) { + // Add a blank line before the attributes + result.push(''); } + result.push(...this.attributes); + return ( super.toString() + `${this.isView ? 'view' : 'model'} ${this.name} {\n` + diff --git a/packages/schema/src/plugins/prisma/schema-generator.ts b/packages/schema/src/plugins/prisma/schema-generator.ts index 7289854bd..ea7a1436c 100644 --- a/packages/schema/src/plugins/prisma/schema-generator.ts +++ b/packages/schema/src/plugins/prisma/schema-generator.ts @@ -27,18 +27,14 @@ import { match } from 'ts-pattern'; import { PRISMA_MINIMUM_VERSION } from '@zenstackhq/runtime'; import { - analyzePolicies, - getDataModels, getDMMF, getLiteral, getLiteralArray, getPrismaVersion, - GUARD_FIELD_NAME, PluginError, PluginOptions, resolved, resolvePath, - TRANSACTION_FIELD_NAME, } from '@zenstackhq/sdk'; import fs from 'fs'; import { writeFile } from 'fs/promises'; @@ -85,7 +81,7 @@ export default class PrismaSchemaGenerator { `; - async generate(model: Model, options: PluginOptions, config?: Record) { + async generate(model: Model, options: PluginOptions, _config?: Record) { const warnings: string[] = []; const prismaVersion = getPrismaVersion(); @@ -108,7 +104,7 @@ export default class PrismaSchemaGenerator { break; case DataModel: - this.generateModel(prisma, decl as DataModel, config); + this.generateModel(prisma, decl as DataModel); break; case GeneratorDecl: @@ -296,53 +292,12 @@ export default class PrismaSchemaGenerator { } } - private generateModel(prisma: PrismaModel, decl: DataModel, config?: Record) { + private generateModel(prisma: PrismaModel, decl: DataModel) { const model = decl.isView ? prisma.addView(decl.name) : prisma.addModel(decl.name); for (const field of decl.fields) { this.generateModelField(model, field); } - if (this.shouldGenerateAuxFields(decl)) { - // generate auxiliary fields for policy check - - // add an "zenstack_guard" field for dealing with boolean conditions - const guardField = model.addField(GUARD_FIELD_NAME, 'Boolean', [ - new PrismaFieldAttribute('@default', [ - new PrismaAttributeArg(undefined, new PrismaAttributeArgValue('Boolean', true)), - ]), - ]); - - if (config?.guardFieldName && config?.guardFieldName !== GUARD_FIELD_NAME) { - // generate a @map to rename field in the database - guardField.addAttribute('@map', [ - new PrismaAttributeArg(undefined, new PrismaAttributeArgValue('String', config.guardFieldName)), - ]); - } - - // add an "zenstack_transaction" field for tracking records created/updated with nested writes - const transactionField = model.addField(TRANSACTION_FIELD_NAME, 'String?'); - - // create an index for "zenstack_transaction" field - model.addAttribute('@@index', [ - new PrismaAttributeArg( - undefined, - new PrismaAttributeArgValue('Array', [ - new PrismaAttributeArgValue('FieldReference', TRANSACTION_FIELD_NAME), - ]) - ), - ]); - - if (config?.transactionFieldName && config?.transactionFieldName !== TRANSACTION_FIELD_NAME) { - // generate a @map to rename field in the database - transactionField.addAttribute('@map', [ - new PrismaAttributeArg( - undefined, - new PrismaAttributeArgValue('String', config.transactionFieldName) - ), - ]); - } - } - for (const attr of decl.attributes.filter((attr) => this.isPrismaAttribute(attr))) { this.generateContainerAttribute(model, attr); } @@ -355,44 +310,6 @@ export default class PrismaSchemaGenerator { decl.comments.forEach((c) => model.addComment(c)); } - private shouldGenerateAuxFields(decl: DataModel) { - if (decl.isView) { - return false; - } - - const { allowAll, denyAll, hasFieldValidation } = analyzePolicies(decl); - - if (!allowAll && !denyAll) { - // has policy conditions - return true; - } - - if (hasFieldValidation) { - return true; - } - - // check if the model is related by other models, if so - // aux fields are needed for nested queries - const root = decl.$container; - for (const model of getDataModels(root)) { - if (model === decl) { - continue; - } - for (const field of model.fields) { - if (field.type.reference?.ref === decl) { - // found a relation with policies - const otherPolicies = analyzePolicies(model); - if ((!otherPolicies.allowAll && !otherPolicies.denyAll) || otherPolicies.hasFieldValidation) { - // the relating side has policies - return true; - } - } - } - } - - return false; - } - private isPrismaAttribute(attr: DataModelAttribute | DataModelFieldAttribute) { if (!attr.decl.ref) { return false; diff --git a/packages/schema/src/plugins/zod/generator.ts b/packages/schema/src/plugins/zod/generator.ts index 267f9dd29..402c43fbc 100644 --- a/packages/schema/src/plugins/zod/generator.ts +++ b/packages/schema/src/plugins/zod/generator.ts @@ -1,6 +1,5 @@ import { ConnectorType, DMMF } from '@prisma/generator-helper'; import { - AUXILIARY_FIELDS, PluginOptions, createProject, emitProject, @@ -120,18 +119,6 @@ async function generateCommonSchemas(project: Project, output: string) { ` import { z } from 'zod'; export const DecimalSchema = z.union([z.number(), z.string(), z.object({d: z.number().array(), e: z.number(), s: z.number()}).passthrough()]); - -// https://stackoverflow.com/a/54487392/20415796 -type OmitDistributive = T extends any ? (T extends object ? OmitRecursively : T) : never; -type OmitRecursively = Omit< - { [P in keyof T]: OmitDistributive }, - K ->; - -/** - * Strips auxiliary fields recursively - */ -export type Purge = OmitRecursively "'" + f + "'").join('|')}>; `, { overwrite: true } ); @@ -197,10 +184,8 @@ async function generateModelSchema(model: DataModel, project: Project, output: s sf.replaceWithText((writer) => { const fields = model.fields.filter( (field) => - !AUXILIARY_FIELDS.includes(field.name) && // scalar fields only - !isDataModel(field.type.reference?.ref) && - !isForeignKeyField(field) + !isDataModel(field.type.reference?.ref) && !isForeignKeyField(field) ); writer.writeLine('/* eslint-disable */'); diff --git a/packages/schema/src/plugins/zod/transformer.ts b/packages/schema/src/plugins/zod/transformer.ts index ea3b76afb..2ad22d2a8 100644 --- a/packages/schema/src/plugins/zod/transformer.ts +++ b/packages/schema/src/plugins/zod/transformer.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import type { DMMF, DMMF as PrismaDMMF } from '@prisma/generator-helper'; import { Model } from '@zenstackhq/language/ast'; -import { AUXILIARY_FIELDS, getPrismaClientImportSpec, getPrismaVersion } from '@zenstackhq/sdk'; +import { getPrismaClientImportSpec, getPrismaVersion } from '@zenstackhq/sdk'; import { checkModelHasModelRelation, findModelByName, isAggregateInputType } from '@zenstackhq/sdk/dmmf-helpers'; import { indentString } from '@zenstackhq/sdk/utils'; import path from 'path'; @@ -54,12 +54,10 @@ export default class Transformer { async generateEnumSchemas() { for (const enumType of this.enumTypes) { const name = upperCaseFirst(enumType.name); - const filteredValues = enumType.values.filter((v) => !AUXILIARY_FIELDS.includes(v)); - const filePath = path.join(Transformer.outputPath, `enums/${name}.schema.ts`); const content = `/* eslint-disable */\n${this.generateImportZodStatement()}\n${this.generateExportSchemaStatement( `${name}`, - `z.enum(${JSON.stringify(filteredValues)})` + `z.enum(${JSON.stringify(enumType.values)})` )}`; this.project.createSourceFile(filePath, content, { overwrite: true }); } @@ -90,7 +88,6 @@ export default class Transformer { generateObjectSchemaFields() { const zodObjectSchemaFields = this.fields - .filter((field) => !AUXILIARY_FIELDS.includes(field.name)) .map((field) => this.generateObjectSchemaField(field)) .flatMap((item) => item) .map((item) => { @@ -270,7 +267,7 @@ export default class Transformer { name = `${name}Type`; origName = `${origName}Type`; } - const outType = `z.ZodType>`; + const outType = `z.ZodType`; return `type SchemaType = ${outType}; export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`; } @@ -327,11 +324,13 @@ export const ${this.name}ObjectSchema: SchemaType = ${schema} as SchemaType;`; } private generateCommonImport() { - let r = `import type { Purge } from '../common';\n`; + let r = ''; if (this.hasDecimal) { r += `import { DecimalSchema } from '../common';\n`; } - r += '\n'; + if (r) { + r += '\n'; + } return r; } diff --git a/packages/schema/tests/generator/prisma-generator.test.ts b/packages/schema/tests/generator/prisma-generator.test.ts index 80c67567e..31dba058c 100644 --- a/packages/schema/tests/generator/prisma-generator.test.ts +++ b/packages/schema/tests/generator/prisma-generator.test.ts @@ -309,42 +309,6 @@ describe('Prisma generator test', () => { expect(post.fields[4].name).toBe('published'); }); - it('custom aux field names', async () => { - const model = await loadModel(` - datasource db { - provider = 'postgresql' - url = env('URL') - } - - model Foo { - id String @id - value Int - @@allow('create', value > 0) - } - `); - - const { name } = tmp.fileSync({ postfix: '.prisma' }); - await new PrismaSchemaGenerator().generate( - model, - { - name: 'Prisma', - provider: '@core/prisma', - schemaPath: 'schema.zmodel', - output: name, - }, - { guardFieldName: 'myGuardField', transactionFieldName: 'myTransactionField' } - ); - - const content = fs.readFileSync(name, 'utf-8'); - await getDMMF({ datamodel: content }); - expect(content).toContain('@map("myGuardField")'); - expect(content).toContain('@map("myTransactionField")'); - expect(content).toContain('value Int\n\n zenstack_guard'); - expect(content).toContain( - 'zenstack_transaction String? @map("myTransactionField")\n\n @@index([zenstack_transaction])' - ); - }); - it('abstract multi files', async () => { const model = await loadDocument(path.join(__dirname, './zmodel/schema.zmodel')); @@ -404,126 +368,6 @@ describe('Prisma generator test', () => { expect(content).toBe(expected); }); - it('no aux fields without policy', async () => { - const model = await loadModel(` - datasource db { - provider = 'postgresql' - url = env('URL') - } - - model Post { - id Int @id() - title String - } - `); - - const { name } = tmp.fileSync({ postfix: '.prisma' }); - await new PrismaSchemaGenerator().generate(model, { - name: 'Prisma', - provider: '@core/prisma', - schemaPath: 'schema.zmodel', - output: name, - format: true, - }); - - const content = fs.readFileSync(name, 'utf-8'); - expect(content).not.toContain('zenstack_guard'); - expect(content).not.toContain('zenstack_transaction'); - }); - - it('aux fields generated due to policies', async () => { - const model = await loadModel(` - datasource db { - provider = 'postgresql' - url = env('URL') - } - - model Post { - id Int @id() - title String @length(1, 32) - @@allow('read', title == "foo") - } - `); - - const { name } = tmp.fileSync({ postfix: '.prisma' }); - await new PrismaSchemaGenerator().generate(model, { - name: 'Prisma', - provider: '@core/prisma', - schemaPath: 'schema.zmodel', - output: name, - format: true, - }); - - const content = fs.readFileSync(name, 'utf-8'); - expect(content).toContain('zenstack_guard'); - expect(content).toContain('zenstack_transaction'); - }); - - it('aux fields generated due to field validation', async () => { - const model = await loadModel(` - datasource db { - provider = 'postgresql' - url = env('URL') - } - - model Post { - id Int @id() - title String @length(1, 32) - } - `); - - const { name } = tmp.fileSync({ postfix: '.prisma' }); - await new PrismaSchemaGenerator().generate(model, { - name: 'Prisma', - provider: '@core/prisma', - schemaPath: 'schema.zmodel', - output: name, - format: true, - }); - - const content = fs.readFileSync(name, 'utf-8'); - expect(content).toContain('zenstack_guard'); - expect(content).toContain('zenstack_transaction'); - }); - - it('aux fields generated due to relationship', async () => { - const model = await loadModel(` - datasource db { - provider = 'postgresql' - url = env('URL') - } - - model User { - id Int @id() - age Int - posts Post[] - @@allow('all', age > 18) - } - - model Post { - id Int @id() - title String - author User @relation(fields: [authorId], references: [id]) - authorId Int - } - `); - - const { name } = tmp.fileSync({ postfix: '.prisma' }); - await new PrismaSchemaGenerator().generate(model, { - name: 'Prisma', - provider: '@core/prisma', - schemaPath: 'schema.zmodel', - output: name, - format: true, - }); - - const content = fs.readFileSync(name, 'utf-8'); - const dmmf = await getDMMF({ datamodel: content }); - const post = dmmf.datamodel?.models?.find((m) => m.name === 'Post'); - expect(post?.fields.map((f) => f.name)).toContain('zenstack_guard'); - expect(post?.fields.map((f) => f.name)).toContain('zenstack_transaction'); - }); - it('view support', async () => { const model = await loadModel(` datasource db { diff --git a/packages/schema/tests/generator/prisma/format.prisma b/packages/schema/tests/generator/prisma/format.prisma index 1eecb4978..22c2d6187 100644 --- a/packages/schema/tests/generator/prisma/format.prisma +++ b/packages/schema/tests/generator/prisma/format.prisma @@ -14,9 +14,4 @@ model Post { title String content String? published Boolean @default(false) - - zenstack_guard Boolean @default(true) - zenstack_transaction String? - - @@index([zenstack_transaction]) } diff --git a/packages/sdk/src/constants.ts b/packages/sdk/src/constants.ts index 08fd6cc18..e038c6958 100644 --- a/packages/sdk/src/constants.ts +++ b/packages/sdk/src/constants.ts @@ -3,7 +3,7 @@ */ export const RUNTIME_PACKAGE = '@zenstackhq/runtime'; -export { AUXILIARY_FIELDS, GUARD_FIELD_NAME, TRANSACTION_FIELD_NAME, CrudFailureReason } from '@zenstackhq/runtime'; +export { CrudFailureReason } from '@zenstackhq/runtime'; /** * Expression context diff --git a/packages/server/src/api/rest/index.ts b/packages/server/src/api/rest/index.ts index 4297cc6dd..fd12d6e32 100644 --- a/packages/server/src/api/rest/index.ts +++ b/packages/server/src/api/rest/index.ts @@ -18,7 +18,7 @@ import z from 'zod'; import { fromZodError } from 'zod-validation-error'; import { LoggerConfig, RequestContext, Response } from '../../types'; import { APIHandlerBase } from '../base'; -import { logWarning, processEntityData, registerCustomSerializers } from '../utils'; +import { logWarning, registerCustomSerializers } from '../utils'; const urlPatterns = { // collection operations @@ -1096,8 +1096,6 @@ class RequestHandler extends APIHandlerBase { throw new Error(`serializer not found for model ${model}`); } - processEntityData(items); - // serialize to JSON:API strcuture const serialized = await serializer.serialize(items, options); diff --git a/packages/server/src/api/rpc/index.ts b/packages/server/src/api/rpc/index.ts index b8615788e..b82995b97 100644 --- a/packages/server/src/api/rpc/index.ts +++ b/packages/server/src/api/rpc/index.ts @@ -11,7 +11,7 @@ import { upperCaseFirst } from 'upper-case-first'; import { fromZodError } from 'zod-validation-error'; import { RequestContext, Response } from '../../types'; import { APIHandlerBase } from '../base'; -import { logError, processEntityData, registerCustomSerializers } from '../utils'; +import { logError, registerCustomSerializers } from '../utils'; registerCustomSerializers(); @@ -137,7 +137,6 @@ class RequestHandler extends APIHandlerBase { } const result = await prisma[model][dbOp](parsedArgs); - processEntityData(result); // eslint-disable-next-line @typescript-eslint/no-explicit-any let response: any = { data: result }; diff --git a/packages/server/src/api/utils.ts b/packages/server/src/api/utils.ts index ba74dd2d3..bc9cc5d71 100644 --- a/packages/server/src/api/utils.ts +++ b/packages/server/src/api/utils.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { AUXILIARY_FIELDS } from '@zenstackhq/runtime'; import { Decimal } from 'decimal.js'; import SuperJSON from 'superjson'; import { LoggerConfig } from '../types'; @@ -28,30 +26,6 @@ export function logInfo(logger: LoggerConfig | undefined | null, message: string } } -function stripAuxFields(data: unknown) { - if (Array.isArray(data)) { - return data.forEach(stripAuxFields); - } else if (data && typeof data === 'object') { - for (const [key, value] of Object.entries(data)) { - if (AUXILIARY_FIELDS.includes(key)) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - delete (data as any)[key]; - } else { - stripAuxFields(value); - } - } - } -} - -/** - * Processes entity data returned from Prisma call. - */ -export function processEntityData(data: any) { - if (data) { - stripAuxFields(data); - } -} - /** * Registers custom superjson serializers. */ diff --git a/packages/server/tests/adapter/express.test.ts b/packages/server/tests/adapter/express.test.ts index e7c908326..518f7ccd0 100644 --- a/packages/server/tests/adapter/express.test.ts +++ b/packages/server/tests/adapter/express.test.ts @@ -48,11 +48,6 @@ describe('Express adapter tests - rpc handler', () => { ]), }) ); - // aux fields should have been removed - expect(data.zenstack_guard).toBeUndefined(); - expect(data.zenstack_transaction).toBeUndefined(); - expect(data.posts[0].zenstack_guard).toBeUndefined(); - expect(data.posts[0].zenstack_transaction).toBeUndefined(); r = await request(app).get(makeUrl('/api/post/findMany')); expect(r.status).toBe(200); diff --git a/packages/server/tests/adapter/fastify.test.ts b/packages/server/tests/adapter/fastify.test.ts index 89aee54cf..a67480d7a 100644 --- a/packages/server/tests/adapter/fastify.test.ts +++ b/packages/server/tests/adapter/fastify.test.ts @@ -55,11 +55,6 @@ describe('Fastify adapter tests - rpc handler', () => { ]), }) ); - // aux fields should have been removed - expect(data.zenstack_guard).toBeUndefined(); - expect(data.zenstack_transaction).toBeUndefined(); - expect(data.posts[0].zenstack_guard).toBeUndefined(); - expect(data.posts[0].zenstack_transaction).toBeUndefined(); r = await app.inject({ method: 'GET', diff --git a/packages/server/tests/api/rpc.test.ts b/packages/server/tests/api/rpc.test.ts index f9ff2155a..1f9b6ed69 100644 --- a/packages/server/tests/api/rpc.test.ts +++ b/packages/server/tests/api/rpc.test.ts @@ -58,10 +58,6 @@ describe('RPC API Handler Tests', () => { ]), }) ); - expect(r.data.zenstack_guard).toBeUndefined(); - expect(r.data.zenstack_transaction).toBeUndefined(); - expect(r.data.posts[0].zenstack_guard).toBeUndefined(); - expect(r.data.posts[0].zenstack_transaction).toBeUndefined(); r = await handleRequest({ method: 'get', diff --git a/tests/integration/tests/cli/config.test.ts b/tests/integration/tests/cli/config.test.ts index d63bfc718..e15558a11 100644 --- a/tests/integration/tests/cli/config.test.ts +++ b/tests/integration/tests/cli/config.test.ts @@ -5,8 +5,6 @@ import * as fs from 'fs'; import * as tmp from 'tmp'; import { createProgram } from '../../../../packages/schema/src/cli'; import { CliError } from '../../../../packages/schema/src/cli/cli-error'; -import { config } from '../../../../packages/schema/src/cli/config'; -import { GUARD_FIELD_NAME, TRANSACTION_FIELD_NAME } from '@zenstackhq/sdk'; describe('CLI Config Tests', () => { let origDir: string; @@ -24,28 +22,14 @@ describe('CLI Config Tests', () => { process.chdir(origDir); }); - it('invalid default config', async () => { - fs.writeFileSync('zenstack.config.json', JSON.stringify({ abc: 'def' })); - - const program = createProgram(); - await expect(program.parseAsync(['init', '--tag', 'latest'], { from: 'user' })).rejects.toBeInstanceOf( - CliError - ); - }); - + // for ensuring backward compatibility only it('valid default config empty', async () => { fs.writeFileSync('zenstack.config.json', JSON.stringify({})); - const program = createProgram(); await program.parseAsync(['init', '--tag', 'latest'], { from: 'user' }); - - // custom config - expect(config.guardFieldName).toBe(GUARD_FIELD_NAME); - - // default value - expect(config.transactionFieldName).toBe(TRANSACTION_FIELD_NAME); }); + // for ensuring backward compatibility only it('valid default config non-empty', async () => { fs.writeFileSync( 'zenstack.config.json', @@ -54,12 +38,6 @@ describe('CLI Config Tests', () => { const program = createProgram(); await program.parseAsync(['init', '--tag', 'latest'], { from: 'user' }); - - // custom config - expect(config.guardFieldName).toBe('myGuardField'); - - // default value - expect(config.transactionFieldName).toBe('myTransactionField'); }); it('custom config file does not exist', async () => { @@ -79,23 +57,10 @@ describe('CLI Config Tests', () => { ).rejects.toThrow(/Config is not a valid JSON file/i); }); + // for ensuring backward compatibility only it('valid custom config file', async () => { fs.writeFileSync('my.config.json', JSON.stringify({ guardFieldName: 'myGuardField' })); const program = createProgram(); await program.parseAsync(['init', '--tag', 'latest', '--config', 'my.config.json'], { from: 'user' }); - - // custom config - expect(config.guardFieldName).toBe('myGuardField'); - - // default value - expect(config.transactionFieldName).toBe(TRANSACTION_FIELD_NAME); - }); - - it('invalid custom config file', async () => { - fs.writeFileSync('my.config.json', JSON.stringify({ abc: 'def' })); - const program = createProgram(); - await expect( - program.parseAsync(['init', '--tag', 'latest', '--config', 'my.config.json'], { from: 'user' }) - ).rejects.toThrow(/Config file my.config.json is not valid/i); }); }); diff --git a/tests/integration/tests/regression/issues.test.ts b/tests/integration/tests/regression/issues.test.ts index 9f1a6d979..8353f8bad 100644 --- a/tests/integration/tests/regression/issues.test.ts +++ b/tests/integration/tests/regression/issues.test.ts @@ -12,49 +12,6 @@ describe('GitHub issues regression', () => { process.chdir(origDir); }); - it('issue 386', async () => { - const { withPolicy } = await loadSchema( - ` - model User { - id String @id @unique @default(uuid()) - posts Post[] - - @@allow('all', true) - } - - model Post { - id String @id @default(uuid()) - title String - published Boolean @default(false) - author User @relation(fields: [authorId], references: [id]) - authorId String - - @@allow('all', contains(title, 'Post')) - } - ` - ); - - const db = withPolicy(); - const created = await db.user.create({ - data: { - posts: { - create: { - title: 'Post 1', - }, - }, - }, - include: { - posts: true, - }, - }); - expect(created.posts[0].zenstack_guard).toBeUndefined(); - expect(created.posts[0].zenstack_transaction).toBeUndefined(); - - const queried = await db.user.findFirst({ include: { posts: true } }); - expect(queried.posts[0].zenstack_guard).toBeUndefined(); - expect(queried.posts[0].zenstack_transaction).toBeUndefined(); - }); - it('issue 389', async () => { const { withPolicy } = await loadSchema(` model model {