Skip to content

Commit

Permalink
chore: remove aux fields (unused since a few release ago) (#662)
Browse files Browse the repository at this point in the history
  • Loading branch information
ymc9 authored Sep 1, 2023
1 parent 522df7a commit b44976d
Show file tree
Hide file tree
Showing 22 changed files with 37 additions and 455 deletions.
3 changes: 1 addition & 2 deletions packages/plugins/openapi/src/rest-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import type { DMMF } from '@prisma/generator-helper';
import {
AUXILIARY_FIELDS,
analyzePolicies,
getDataModels,
hasAttribute,
Expand Down Expand Up @@ -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<string, OAPI.SchemaObject> = {};
const relationships: Record<string, OAPI.ReferenceObject> = {};
Expand Down
17 changes: 7 additions & 10 deletions packages/plugins/openapi/src/rpc-generator.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -681,17 +681,16 @@ 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;
}

private generateEntityComponent(model: DMMF.Model): OAPI.SchemaObject {
const properties: Record<string, OAPI.ReferenceObject | OAPI.SchemaObject> = {};

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);
Expand Down Expand Up @@ -721,8 +720,7 @@ export class RPCOpenAPIGenerator extends OpenAPIGeneratorBase {

private generateInputComponent(input: DMMF.InputType): OAPI.SchemaObject {
const properties: Record<string, OAPI.ReferenceObject | OAPI.SchemaObject> = {};
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) =>
Expand All @@ -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<string, OAPI.ReferenceObject | OAPI.SchemaObject> = {};
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':
Expand All @@ -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;
}

Expand Down
15 changes: 0 additions & 15 deletions packages/runtime/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
8 changes: 0 additions & 8 deletions packages/runtime/src/enhancements/policy/policy-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions packages/runtime/src/enhancements/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
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';

/**
* 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) : [];
}

/**
Expand Down
9 changes: 2 additions & 7 deletions packages/schema/src/cli/config.ts
Original file line number Diff line number Diff line change
@@ -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<typeof schema>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(' ? ');
Expand All @@ -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(' ? ');
Expand Down
18 changes: 7 additions & 11 deletions packages/schema/src/plugins/prisma/prisma-builder.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { AUXILIARY_FIELDS } from '@zenstackhq/sdk';
import indentString from './indent-string';

/**
Expand Down Expand Up @@ -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` +
Expand Down
89 changes: 3 additions & 86 deletions packages/schema/src/plugins/prisma/schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -85,7 +81,7 @@ export default class PrismaSchemaGenerator {
`;

async generate(model: Model, options: PluginOptions, config?: Record<string, string>) {
async generate(model: Model, options: PluginOptions, _config?: Record<string, string>) {
const warnings: string[] = [];

const prismaVersion = getPrismaVersion();
Expand All @@ -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:
Expand Down Expand Up @@ -296,53 +292,12 @@ export default class PrismaSchemaGenerator {
}
}

private generateModel(prisma: PrismaModel, decl: DataModel, config?: Record<string, string>) {
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);
}
Expand All @@ -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;
Expand Down
17 changes: 1 addition & 16 deletions packages/schema/src/plugins/zod/generator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { ConnectorType, DMMF } from '@prisma/generator-helper';
import {
AUXILIARY_FIELDS,
PluginOptions,
createProject,
emitProject,
Expand Down Expand Up @@ -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, K extends PropertyKey> = T extends any ? (T extends object ? OmitRecursively<T, K> : T) : never;
type OmitRecursively<T extends any, K extends PropertyKey> = Omit<
{ [P in keyof T]: OmitDistributive<T[P], K> },
K
>;
/**
* Strips auxiliary fields recursively
*/
export type Purge<T> = OmitRecursively<T, ${AUXILIARY_FIELDS.map((f) => "'" + f + "'").join('|')}>;
`,
{ overwrite: true }
);
Expand Down Expand Up @@ -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 */');
Expand Down
Loading

0 comments on commit b44976d

Please sign in to comment.