Skip to content

Commit 6f7cb0e

Browse files
authored
fix: handle @@ignore models properly in plugins (#283)
1 parent be0a88d commit 6f7cb0e

File tree

27 files changed

+1122
-144
lines changed

27 files changed

+1122
-144
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "zenstack-monorepo",
3-
"version": "1.0.0-alpha.79",
3+
"version": "1.0.0-alpha.81",
44
"description": "",
55
"scripts": {
66
"build": "pnpm -r build",

packages/language/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/language",
3-
"version": "1.0.0-alpha.79",
3+
"version": "1.0.0-alpha.81",
44
"displayName": "ZenStack modeling language compiler",
55
"description": "ZenStack modeling language compiler",
66
"homepage": "https://zenstack.dev",

packages/next/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenstackhq/next",
3-
"version": "1.0.0-alpha.79",
3+
"version": "1.0.0-alpha.81",
44
"displayName": "ZenStack Next.js integration",
55
"description": "ZenStack Next.js integration",
66
"homepage": "https://zenstack.dev",

packages/plugins/openapi/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/openapi",
33
"displayName": "ZenStack Plugin and Runtime for OpenAPI",
4-
"version": "1.0.0-alpha.79",
4+
"version": "1.0.0-alpha.81",
55
"description": "ZenStack plugin and runtime supporting OpenAPI",
66
"main": "index.js",
77
"repository": {

packages/plugins/openapi/src/generator.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Inspired by: https://github.com/omar-dulaimi/prisma-trpc-generator
22

33
import { DMMF } from '@prisma/generator-helper';
4-
import { AUXILIARY_FIELDS, hasAttribute, PluginError, PluginOptions } from '@zenstackhq/sdk';
4+
import { AUXILIARY_FIELDS, getDataModels, hasAttribute, PluginError, PluginOptions } from '@zenstackhq/sdk';
55
import { DataModel, isDataModel, type Model } from '@zenstackhq/sdk/ast';
66
import {
77
addMissingInputObjectTypesForAggregate,
@@ -28,6 +28,7 @@ export class OpenAPIGenerator {
2828
private usedComponents: Set<string> = new Set<string>();
2929
private aggregateOperationSupport: AggregateOperationSupport;
3030
private includedModels: DataModel[];
31+
private warnings: string[] = [];
3132

3233
constructor(private model: Model, private options: PluginOptions, private dmmf: DMMF.Document) {}
3334

@@ -40,9 +41,7 @@ export class OpenAPIGenerator {
4041
// input types
4142
this.inputObjectTypes.push(...this.dmmf.schema.inputObjectTypes.prisma);
4243
this.outputObjectTypes.push(...this.dmmf.schema.outputObjectTypes.prisma);
43-
this.includedModels = this.model.declarations.filter(
44-
(d): d is DataModel => isDataModel(d) && !hasAttribute(d, '@@openapi.ignore')
45-
);
44+
this.includedModels = getDataModels(this.model).filter((d) => !hasAttribute(d, '@@openapi.ignore'));
4645

4746
// add input object types that are missing from Prisma dmmf
4847
addMissingInputObjectTypesForModelArgs(this.inputObjectTypes, this.dmmf.datamodel.models);
@@ -80,6 +79,8 @@ export class OpenAPIGenerator {
8079
} else {
8180
fs.writeFileSync(output, JSON.stringify(openapi, undefined, 2));
8281
}
82+
83+
return this.warnings;
8384
}
8485

8586
private pruneComponents(components: OAPI.ComponentsObject) {
@@ -148,7 +149,7 @@ export class OpenAPIGenerator {
148149
...this.generatePathsForModel(model, zmodel, components),
149150
} as OAPI.PathsObject;
150151
} else {
151-
console.warn(`Unable to load ZModel definition for: ${model.name}}`);
152+
this.warnings.push(`Unable to load ZModel definition for: ${model.name}}`);
152153
}
153154
}
154155
}
@@ -159,13 +160,14 @@ export class OpenAPIGenerator {
159160
model: DMMF.Model,
160161
zmodel: DataModel,
161162
components: OAPI.ComponentsObject
162-
): OAPI.PathItemObject {
163+
): OAPI.PathItemObject | undefined {
163164
const result: OAPI.PathItemObject & Record<string, unknown> = {};
164165
// eslint-disable-next-line @typescript-eslint/no-explicit-any
165166
const ops: (DMMF.ModelMapping & { createOne?: string | null } & Record<string, any>) | undefined =
166167
this.dmmf.mappings.modelOperations.find((ops) => ops.model === model.name);
167168
if (!ops) {
168-
throw new PluginError(`No operations found for model ${model.name}`);
169+
this.warnings.push(`Unable to find mapping for model ${model.name}`);
170+
return undefined;
169171
}
170172

171173
type OperationDefinition = {
Lines changed: 55 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,70 @@
11
/// <reference types="@types/jest" />
22

3-
import { getDMMF } from '@prisma/internals';
43
import OpenAPIParser from '@readme/openapi-parser';
5-
import * as fs from 'fs';
4+
import { loadZModelAndDmmf } from '@zenstackhq/testtools';
65
import * as tmp from 'tmp';
7-
import { loadDocument } from 'zenstack/cli/cli-util';
8-
import prismaPlugin from 'zenstack/plugins/prisma';
96
import generate from '../src';
107

11-
async function loadZModelAndDmmf(content: string) {
12-
const prelude = `
13-
datasource db {
14-
provider = 'postgresql'
15-
url = env('DATABASE_URL')
16-
}
17-
`;
18-
19-
const { name: modelFile } = tmp.fileSync({ postfix: '.zmodel' });
20-
fs.writeFileSync(modelFile, `${prelude}\n${content}`);
21-
22-
const model = await loadDocument(modelFile);
23-
24-
const { name: prismaFile } = tmp.fileSync({ postfix: '.prisma' });
25-
await prismaPlugin(model, { schemaPath: modelFile, output: prismaFile, generateClient: false });
26-
27-
const prismaContent = fs.readFileSync(prismaFile, { encoding: 'utf-8' });
28-
29-
const dmmf = await getDMMF({ datamodel: prismaContent });
30-
return { model, dmmf, modelFile };
31-
}
32-
338
describe('Open API Plugin Tests', () => {
349
it('run plugin', async () => {
3510
const { model, dmmf, modelFile } = await loadZModelAndDmmf(`
36-
plugin openapi {
37-
provider = '${process.cwd()}/dist'
38-
}
11+
plugin openapi {
12+
provider = '${process.cwd()}/dist'
13+
}
3914
40-
enum Role {
41-
USER
42-
ADMIN
43-
}
15+
enum Role {
16+
USER
17+
ADMIN
18+
}
4419
45-
model User {
46-
id String @id
47-
createdAt DateTime @default(now())
48-
updatedAt DateTime @updatedAt
49-
email String @unique
50-
role Role @default(USER)
51-
posts Post[]
52-
53-
@@openapi.meta({
54-
findMany: {
55-
description: 'Find users matching the given conditions'
56-
},
57-
delete: {
58-
method: 'put',
59-
path: 'dodelete',
60-
description: 'Delete a unique user',
61-
summary: 'Delete a user yeah yeah',
62-
tags: ['delete', 'user']
63-
},
64-
})
65-
}
66-
67-
model Post {
68-
id String @id
69-
createdAt DateTime @default(now())
70-
updatedAt DateTime @updatedAt
71-
title String
72-
author User? @relation(fields: [authorId], references: [id])
73-
authorId String?
74-
published Boolean @default(false)
75-
viewCount Int @default(0)
76-
77-
@@openapi.meta({
78-
findMany: {
79-
ignore: true
80-
}
81-
})
82-
}
20+
model User {
21+
id String @id
22+
createdAt DateTime @default(now())
23+
updatedAt DateTime @updatedAt
24+
email String @unique
25+
role Role @default(USER)
26+
posts Post[]
27+
28+
@@openapi.meta({
29+
findMany: {
30+
description: 'Find users matching the given conditions'
31+
},
32+
delete: {
33+
method: 'put',
34+
path: 'dodelete',
35+
description: 'Delete a unique user',
36+
summary: 'Delete a user yeah yeah',
37+
tags: ['delete', 'user']
38+
},
39+
})
40+
}
8341
84-
model Foo {
85-
id String @id
42+
model Post {
43+
id String @id
44+
createdAt DateTime @default(now())
45+
updatedAt DateTime @updatedAt
46+
title String
47+
author User? @relation(fields: [authorId], references: [id])
48+
authorId String?
49+
published Boolean @default(false)
50+
viewCount Int @default(0)
51+
52+
@@openapi.meta({
53+
findMany: {
54+
ignore: true
55+
}
56+
})
57+
}
8658
87-
@@openapi.ignore
88-
}
59+
model Foo {
60+
id String @id
61+
@@openapi.ignore
62+
}
63+
64+
model Bar {
65+
id String @id
66+
@@ignore
67+
}
8968
`);
9069

9170
const { name: output } = tmp.fileSync({ postfix: '.yaml' });
@@ -102,5 +81,6 @@ describe('Open API Plugin Tests', () => {
10281
expect(api.paths?.['/post/findMany']).toBeUndefined();
10382

10483
expect(api.paths?.['/foo/findMany']).toBeUndefined();
84+
expect(api.paths?.['/bar/findMany']).toBeUndefined();
10585
});
10686
});

packages/plugins/react/jest.config.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* For a detailed explanation regarding each configuration property and type check, visit:
3+
* https://jestjs.io/docs/configuration
4+
*/
5+
6+
export default {
7+
// Automatically clear mock calls, instances, contexts and results before every test
8+
clearMocks: true,
9+
10+
// Indicates whether the coverage information should be collected while executing the test
11+
collectCoverage: true,
12+
13+
// The directory where Jest should output its coverage files
14+
coverageDirectory: 'tests/coverage',
15+
16+
// An array of regexp pattern strings used to skip coverage collection
17+
coveragePathIgnorePatterns: ['/node_modules/', '/tests/'],
18+
19+
// Indicates which provider should be used to instrument code for coverage
20+
coverageProvider: 'v8',
21+
22+
// A list of reporter names that Jest uses when writing coverage reports
23+
coverageReporters: ['json', 'text', 'lcov', 'clover'],
24+
25+
// A map from regular expressions to paths to transformers
26+
transform: { '^.+\\.tsx?$': 'ts-jest' },
27+
28+
testTimeout: 300000,
29+
};

packages/plugins/react/package.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/react",
33
"displayName": "ZenStack plugin and runtime for ReactJS",
4-
"version": "1.0.0-alpha.79",
4+
"version": "1.0.0-alpha.81",
55
"description": "ZenStack plugin and runtime for ReactJS",
66
"main": "index.js",
77
"repository": {
@@ -37,9 +37,14 @@
3737
"react-dom": "^17.0.2 || ^18"
3838
},
3939
"devDependencies": {
40+
"@types/jest": "^29.5.0",
4041
"@types/react": "^18.0.26",
42+
"@types/tmp": "^0.2.3",
4143
"copyfiles": "^2.4.1",
44+
"jest": "^29.5.0",
4245
"rimraf": "^3.0.2",
43-
"typescript": "^4.9.4"
46+
"ts-jest": "^29.0.5",
47+
"typescript": "^4.9.4",
48+
"@zenstackhq/testtools": "workspace:*"
4449
}
4550
}

0 commit comments

Comments
 (0)