From a02182cf6783e956789d8e19733dbe2af83dffdc Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Fri, 30 Jun 2023 23:52:45 +0800 Subject: [PATCH 1/4] fix: add enum import to zod generation --- packages/schema/src/plugins/zod/generator.ts | 20 ++++++++++++++++++-- packages/sdk/src/utils.ts | 4 ++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/schema/src/plugins/zod/generator.ts b/packages/schema/src/plugins/zod/generator.ts index aeb7bdd83..5de19f66b 100644 --- a/packages/schema/src/plugins/zod/generator.ts +++ b/packages/schema/src/plugins/zod/generator.ts @@ -11,8 +11,10 @@ import { isForeignKeyField, resolvePath, saveProject, + isEnumFieldReference, + getPrismaClientImportSpec, } from '@zenstackhq/sdk'; -import { DataModel, DataSource, Model, isDataModel, isDataSource, isEnum } from '@zenstackhq/sdk/ast'; +import { DataModel, DataSource, EnumField, Model, isDataModel, isDataSource, isEnum } from '@zenstackhq/sdk/ast'; import { AggregateOperationSupport, addMissingInputObjectTypes, @@ -26,6 +28,7 @@ import Transformer from './transformer'; import removeDir from './utils/removeDir'; import { upperCaseFirst } from 'upper-case-first'; import { makeFieldSchema, makeValidationRefinements } from './utils/schema-gen'; +import { streamAllContents } from 'langium'; export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.Document) { let output = options.output as string; @@ -178,6 +181,19 @@ async function generateModelSchema(model: DataModel, project: Project, output: s sf.replaceWithText((writer) => { writer.writeLine('/* eslint-disable */'); + // import enums + const importEnums = new Set(); + for (const node of streamAllContents(model)) { + if (isEnumFieldReference(node)) { + const field = node.target.ref as EnumField; + importEnums.add(field.$container.name); + } + } + if (importEnums.size > 0) { + const prismaImport = getPrismaClientImportSpec(model.$container, path.join(output, 'models')); + writer.writeLine(`import { ${[...importEnums].join(', ')} } from '${prismaImport}';`); + } + const fields = model.fields.filter( (field) => !AUXILIARY_FIELDS.includes(field.name) && @@ -205,9 +221,9 @@ async function generateModelSchema(model: DataModel, project: Project, output: s }); writer.writeLine(');'); + // compile "@@validate" to ".refine" const refinements = makeValidationRefinements(model); if (refinements.length > 0) { - console.log('Generated refinements:', refinements); writer.writeLine(`function refine(schema: z.ZodType) { return schema${refinements.join('\n')}; }`); } diff --git a/packages/sdk/src/utils.ts b/packages/sdk/src/utils.ts index 3a1cdb72d..3b26c01f1 100644 --- a/packages/sdk/src/utils.ts +++ b/packages/sdk/src/utils.ts @@ -133,8 +133,8 @@ export function getAttributeArgLiteral( return undefined; } -export function isEnumFieldReference(expr: Expression): expr is ReferenceExpr { - return isReferenceExpr(expr) && isEnumField(expr.target.ref); +export function isEnumFieldReference(node: AstNode): node is ReferenceExpr { + return isReferenceExpr(node) && isEnumField(node.target.ref); } /** From 1a0921e117a527b2b67cb5fc16d4f5e96c9db2bb Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Sat, 1 Jul 2023 00:06:48 +0800 Subject: [PATCH 2/4] fix tests --- packages/schema/src/plugins/zod/generator.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/schema/src/plugins/zod/generator.ts b/packages/schema/src/plugins/zod/generator.ts index 5de19f66b..6e0683fc2 100644 --- a/packages/schema/src/plugins/zod/generator.ts +++ b/packages/schema/src/plugins/zod/generator.ts @@ -29,6 +29,7 @@ import removeDir from './utils/removeDir'; import { upperCaseFirst } from 'upper-case-first'; import { makeFieldSchema, makeValidationRefinements } from './utils/schema-gen'; import { streamAllContents } from 'langium'; +import { isFromStdlib } from 'src/language-server/utils'; export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.Document) { let output = options.output as string; @@ -206,7 +207,11 @@ async function generateModelSchema(model: DataModel, project: Project, output: s // import enums for (const field of fields) { - if (field.type.reference?.ref && isEnum(field.type.reference?.ref)) { + if ( + field.type.reference?.ref && + isEnum(field.type.reference?.ref) && + !isFromStdlib(field.type.reference?.ref) + ) { const name = upperCaseFirst(field.type.reference?.ref.name); writer.writeLine(`import { ${name}Schema } from '../enums/${name}.schema';`); } From 1dcb5fc67ce816e36cd9ab65296c3f9738afb992 Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Sat, 1 Jul 2023 00:12:02 +0800 Subject: [PATCH 3/4] fix build --- packages/schema/src/plugins/zod/generator.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/schema/src/plugins/zod/generator.ts b/packages/schema/src/plugins/zod/generator.ts index 6e0683fc2..631f134e1 100644 --- a/packages/schema/src/plugins/zod/generator.ts +++ b/packages/schema/src/plugins/zod/generator.ts @@ -7,12 +7,12 @@ import { emitProject, getDataModels, getLiteral, + getPrismaClientImportSpec, hasAttribute, + isEnumFieldReference, isForeignKeyField, resolvePath, saveProject, - isEnumFieldReference, - getPrismaClientImportSpec, } from '@zenstackhq/sdk'; import { DataModel, DataSource, EnumField, Model, isDataModel, isDataSource, isEnum } from '@zenstackhq/sdk/ast'; import { @@ -21,15 +21,15 @@ import { resolveAggregateOperationSupport, } from '@zenstackhq/sdk/dmmf-helpers'; import { promises as fs } from 'fs'; +import { streamAllContents } from 'langium'; import path from 'path'; import { Project } from 'ts-morph'; +import { upperCaseFirst } from 'upper-case-first'; +import { isFromStdlib } from '../../language-server/utils'; import { getDefaultOutputFolder } from '../plugin-utils'; import Transformer from './transformer'; import removeDir from './utils/removeDir'; -import { upperCaseFirst } from 'upper-case-first'; import { makeFieldSchema, makeValidationRefinements } from './utils/schema-gen'; -import { streamAllContents } from 'langium'; -import { isFromStdlib } from 'src/language-server/utils'; export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.Document) { let output = options.output as string; From c15560d77896eeca8634d455ea4c79f7a59f7e4e Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Sat, 1 Jul 2023 07:58:19 +0800 Subject: [PATCH 4/4] fix test --- packages/schema/src/plugins/zod/generator.ts | 33 +++++++++----------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/packages/schema/src/plugins/zod/generator.ts b/packages/schema/src/plugins/zod/generator.ts index 631f134e1..08734dc0c 100644 --- a/packages/schema/src/plugins/zod/generator.ts +++ b/packages/schema/src/plugins/zod/generator.ts @@ -180,14 +180,25 @@ async function generateModelSchema(model: DataModel, project: Project, output: s overwrite: true, }); sf.replaceWithText((writer) => { + const fields = model.fields.filter( + (field) => + !AUXILIARY_FIELDS.includes(field.name) && + // scalar fields only + !isDataModel(field.type.reference?.ref) && + !isForeignKeyField(field) + ); + writer.writeLine('/* eslint-disable */'); + writer.writeLine(`import { z } from 'zod';`); - // import enums + // import user-defined enums from Prisma as they might be referenced in the expressions const importEnums = new Set(); for (const node of streamAllContents(model)) { if (isEnumFieldReference(node)) { const field = node.target.ref as EnumField; - importEnums.add(field.$container.name); + if (!isFromStdlib(field.$container)) { + importEnums.add(field.$container.name); + } } } if (importEnums.size > 0) { @@ -195,23 +206,9 @@ async function generateModelSchema(model: DataModel, project: Project, output: s writer.writeLine(`import { ${[...importEnums].join(', ')} } from '${prismaImport}';`); } - const fields = model.fields.filter( - (field) => - !AUXILIARY_FIELDS.includes(field.name) && - // scalar fields only - !isDataModel(field.type.reference?.ref) && - !isForeignKeyField(field) - ); - - writer.writeLine(`import { z } from 'zod';`); - - // import enums + // import enum schemas for (const field of fields) { - if ( - field.type.reference?.ref && - isEnum(field.type.reference?.ref) && - !isFromStdlib(field.type.reference?.ref) - ) { + if (field.type.reference?.ref && isEnum(field.type.reference?.ref)) { const name = upperCaseFirst(field.type.reference?.ref.name); writer.writeLine(`import { ${name}Schema } from '../enums/${name}.schema';`); }