Skip to content

Commit 4b70853

Browse files
authored
fix: duplicated zod schema imported when there're multiple fields with an enum type (#633)
1 parent 4776685 commit 4b70853

File tree

12 files changed

+112
-158
lines changed

12 files changed

+112
-158
lines changed

packages/schema/src/plugins/zod/generator.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,10 +220,14 @@ async function generateModelSchema(model: DataModel, project: Project, output: s
220220
}
221221

222222
// import enum schemas
223+
const importedEnumSchemas = new Set<string>();
223224
for (const field of fields) {
224225
if (field.type.reference?.ref && isEnum(field.type.reference?.ref)) {
225226
const name = upperCaseFirst(field.type.reference?.ref.name);
226-
writer.writeLine(`import { ${name}Schema } from '../enums/${name}.schema';`);
227+
if (!importedEnumSchemas.has(name)) {
228+
writer.writeLine(`import { ${name}Schema } from '../enums/${name}.schema';`);
229+
importedEnumSchemas.add(name);
230+
}
227231
}
228232
}
229233

packages/testtools/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323
"@zenstackhq/runtime": "workspace:*",
2424
"@zenstackhq/sdk": "workspace:*",
2525
"json5": "^2.2.3",
26+
"pg": "^8.11.1",
2627
"tmp": "^0.2.1",
2728
"zenstack": "workspace:*"
2829
},
2930
"devDependencies": {
3031
"@types/node": "^18.0.0",
32+
"@types/pg": "^8.10.2",
3133
"@types/tmp": "^0.2.3",
3234
"copyfiles": "^2.4.1",
3335
"rimraf": "^3.0.2",

packages/testtools/src/db.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Pool } from 'pg';
2+
3+
const USERNAME = 'postgres';
4+
const PASSWORD = 'abc123';
5+
6+
export async function createPostgresDb(db: string) {
7+
const pool = new Pool({ user: USERNAME, password: PASSWORD });
8+
await pool.query(`DROP DATABASE IF EXISTS "${db}";`);
9+
await pool.query(`CREATE DATABASE "${db}";`);
10+
return `postgresql://${USERNAME}:${PASSWORD}@localhost:5432/${db}`;
11+
}
12+
13+
export async function dropPostgresDb(db: string) {
14+
const pool = new Pool({ user: USERNAME, password: PASSWORD });
15+
await pool.query(`DROP DATABASE IF EXISTS "${db}";`);
16+
}

packages/testtools/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './schema';
2+
export * from './db';

packages/testtools/src/schema.ts

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,11 @@ export function getWorkspaceNpmCacheFolder(start: string) {
7070
return root ? path.join(root, '.npmcache') : './.npmcache';
7171
}
7272

73-
const MODEL_PRELUDE = `
73+
function makePrelude(options: SchemaLoadOptions) {
74+
return `
7475
datasource db {
75-
provider = 'sqlite'
76-
url = 'file:./test.db'
76+
provider = '${options.provider}'
77+
url = '${options.dbUrl}'
7778
}
7879
7980
generator js {
@@ -83,26 +84,10 @@ generator js {
8384
8485
plugin zod {
8586
provider = '@core/zod'
86-
modelOnly = true
87+
modelOnly = ${!options.fullZod}
8788
}
8889
`;
89-
90-
const MODEL_PRELUDE_FULL_ZOD = `
91-
datasource db {
92-
provider = 'sqlite'
93-
url = 'file:./test.db'
94-
}
95-
96-
generator js {
97-
provider = 'prisma-client-js'
98-
previewFeatures = ['clientExtensions']
99-
}
100-
101-
plugin zod {
102-
provider = '@core/zod'
103-
modelOnly = false
10490
}
105-
`;
10691

10792
export type SchemaLoadOptions = {
10893
addPrelude?: boolean;
@@ -112,6 +97,8 @@ export type SchemaLoadOptions = {
11297
compile?: boolean;
11398
customSchemaFilePath?: string;
11499
logPrismaQuery?: boolean;
100+
provider?: 'sqlite' | 'postgresql';
101+
dbUrl?: string;
115102
};
116103

117104
const defaultOptions: SchemaLoadOptions = {
@@ -121,6 +108,8 @@ const defaultOptions: SchemaLoadOptions = {
121108
extraDependencies: [],
122109
compile: false,
123110
logPrismaQuery: false,
111+
provider: 'sqlite',
112+
dbUrl: 'file:./test.db',
124113
};
125114

126115
export async function loadSchemaFromFile(schemaFile: string, options?: SchemaLoadOptions) {
@@ -164,7 +153,7 @@ export async function loadSchema(schema: string, options?: SchemaLoadOptions) {
164153
zmodelPath = path.join(projectRoot, fileName);
165154
if (opt.addPrelude) {
166155
// plugin need to be added after import statement
167-
fileContent = `${fileContent}\n${opt.fullZod ? MODEL_PRELUDE_FULL_ZOD : MODEL_PRELUDE}`;
156+
fileContent = `${fileContent}\n${makePrelude(opt)}`;
168157
}
169158
}
170159

@@ -174,7 +163,7 @@ export async function loadSchema(schema: string, options?: SchemaLoadOptions) {
174163
});
175164
} else {
176165
schema = schema.replaceAll('$projectRoot', projectRoot);
177-
const content = opt.addPrelude ? `${opt.fullZod ? MODEL_PRELUDE_FULL_ZOD : MODEL_PRELUDE}\n${schema}` : schema;
166+
const content = opt.addPrelude ? `${makePrelude(opt)}\n${schema}` : schema;
178167
if (opt.customSchemaFilePath) {
179168
zmodelPath = path.join(projectRoot, opt.customSchemaFilePath);
180169
fs.mkdirSync(path.dirname(zmodelPath), { recursive: true });

pnpm-lock.yaml

Lines changed: 10 additions & 39 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/integration/tests/enhancements/with-policy/field-comparison.test.ts

Lines changed: 10 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,33 @@
1-
import { loadSchema } from '@zenstackhq/testtools';
1+
import { loadSchema, createPostgresDb, dropPostgresDb } from '@zenstackhq/testtools';
22
import path from 'path';
3-
import { Pool } from 'pg';
43

54
const DB_NAME = 'field-comparison';
65

76
describe('WithPolicy: field comparison tests', () => {
87
let origDir: string;
8+
let dbUrl: string;
99
let prisma: any;
1010

11-
const pool = new Pool({ user: 'postgres', password: 'abc123' });
12-
1311
beforeAll(async () => {
1412
origDir = path.resolve('.');
1513
});
1614

1715
beforeEach(async () => {
18-
await pool.query(`DROP DATABASE IF EXISTS "${DB_NAME}";`);
19-
await pool.query(`CREATE DATABASE "${DB_NAME}";`);
16+
dbUrl = await createPostgresDb(DB_NAME);
2017
});
2118

2219
afterEach(async () => {
23-
process.chdir(origDir);
2420
if (prisma) {
2521
await prisma.$disconnect();
22+
prisma = undefined;
2623
}
27-
await pool.query(`DROP DATABASE IF EXISTS "${DB_NAME}";`);
24+
await dropPostgresDb(DB_NAME);
25+
process.chdir(origDir);
2826
});
2927

3028
it('field comparison success with input check', async () => {
3129
const r = await loadSchema(
3230
`
33-
datasource db {
34-
provider = 'postgresql'
35-
url = 'postgres://postgres:abc123@localhost:5432/${DB_NAME}'
36-
}
37-
38-
generator js {
39-
provider = 'prisma-client-js'
40-
}
41-
4231
model Model {
4332
id String @id @default(uuid())
4433
x Int
@@ -48,7 +37,7 @@ describe('WithPolicy: field comparison tests', () => {
4837
@@allow('read', true)
4938
}
5039
`,
51-
{ addPrelude: false }
40+
{ provider: 'postgresql', dbUrl }
5241
);
5342

5443
prisma = r.prisma;
@@ -60,15 +49,6 @@ describe('WithPolicy: field comparison tests', () => {
6049
it('field comparison success with policy check', async () => {
6150
const r = await loadSchema(
6251
`
63-
datasource db {
64-
provider = 'postgresql'
65-
url = 'postgres://postgres:abc123@localhost:5432/${DB_NAME}'
66-
}
67-
68-
generator js {
69-
provider = 'prisma-client-js'
70-
}
71-
7252
model Model {
7353
id String @id @default(uuid())
7454
x Int @default(0)
@@ -78,7 +58,7 @@ describe('WithPolicy: field comparison tests', () => {
7858
@@allow('read', true)
7959
}
8060
`,
81-
{ addPrelude: false }
61+
{ provider: 'postgresql', dbUrl }
8262
);
8363

8464
prisma = r.prisma;
@@ -90,15 +70,6 @@ describe('WithPolicy: field comparison tests', () => {
9070
it('field in operator success with input check', async () => {
9171
const r = await loadSchema(
9272
`
93-
datasource db {
94-
provider = 'postgresql'
95-
url = 'postgres://postgres:abc123@localhost:5432/${DB_NAME}'
96-
}
97-
98-
generator js {
99-
provider = 'prisma-client-js'
100-
}
101-
10273
model Model {
10374
id String @id @default(uuid())
10475
x String
@@ -108,7 +79,7 @@ describe('WithPolicy: field comparison tests', () => {
10879
@@allow('read', x in y)
10980
}
11081
`,
111-
{ addPrelude: false }
82+
{ provider: 'postgresql', dbUrl }
11283
);
11384

11485
prisma = r.prisma;
@@ -120,15 +91,6 @@ describe('WithPolicy: field comparison tests', () => {
12091
it('field in operator success with policy check', async () => {
12192
const r = await loadSchema(
12293
`
123-
datasource db {
124-
provider = 'postgresql'
125-
url = 'postgres://postgres:abc123@localhost:5432/${DB_NAME}'
126-
}
127-
128-
generator js {
129-
provider = 'prisma-client-js'
130-
}
131-
13294
model Model {
13395
id String @id @default(uuid())
13496
x String @default('x')
@@ -138,7 +100,7 @@ describe('WithPolicy: field comparison tests', () => {
138100
@@allow('read', x in y)
139101
}
140102
`,
141-
{ addPrelude: false }
103+
{ provider: 'postgresql', dbUrl }
142104
);
143105

144106
prisma = r.prisma;

0 commit comments

Comments
 (0)