Skip to content

Commit cef96d4

Browse files
authored
feat: add prisma passthrough attribute for working around discripancies between zmodel and prisma (#245)
1 parent 93cb6bf commit cef96d4

File tree

26 files changed

+1618
-90
lines changed

26 files changed

+1618
-90
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.58",
3+
"version": "1.0.0-alpha.60",
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.58",
3+
"version": "1.0.0-alpha.60",
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.58",
3+
"version": "1.0.0-alpha.60",
44
"displayName": "ZenStack Next.js integration",
55
"description": "ZenStack Next.js integration",
66
"homepage": "https://zenstack.dev",

packages/plugins/react/package.json

Lines changed: 1 addition & 1 deletion
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.58",
4+
"version": "1.0.0-alpha.60",
55
"description": "ZenStack plugin and runtime for ReactJS",
66
"main": "index.js",
77
"repository": {

packages/plugins/trpc/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/trpc",
33
"displayName": "ZenStack plugin for tRPC",
4-
"version": "1.0.0-alpha.58",
4+
"version": "1.0.0-alpha.60",
55
"description": "ZenStack plugin for tRPC",
66
"main": "index.js",
77
"repository": {

packages/runtime/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@zenstackhq/runtime",
33
"displayName": "ZenStack Runtime Library",
4-
"version": "1.0.0-alpha.58",
4+
"version": "1.0.0-alpha.60",
55
"description": "Runtime of ZenStack for both client-side and server-side environments.",
66
"repository": {
77
"type": "git",

packages/schema/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"publisher": "zenstack",
44
"displayName": "ZenStack Language Tools",
55
"description": "A toolkit for building secure CRUD apps with Next.js + Typescript",
6-
"version": "1.0.0-alpha.58",
6+
"version": "1.0.0-alpha.60",
77
"author": {
88
"name": "ZenStack Team"
99
},

packages/schema/src/language-server/validator/datamodel-validator.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { IssueCodes, SCALAR_TYPES } from '../constants';
1212
import { AstValidator } from '../types';
1313
import { getIdFields, getUniqueFields } from '../utils';
1414
import { validateAttributeApplication, validateDuplicatedDeclarations } from './utils';
15+
import { getLiteral } from '@zenstackhq/sdk';
1516

1617
/**
1718
* Validates data model declarations.
@@ -174,13 +175,15 @@ export default class DataModelValidator implements AstValidator<DataModel> {
174175
const oppositeModelFields = field.type.reference?.ref?.fields as DataModelField[];
175176
if (oppositeModelFields) {
176177
for (const oppositeField of oppositeModelFields) {
177-
const { name: oppositeRelationName } = this.parseRelation(oppositeField);
178-
if (
179-
oppositeRelationName === relationName &&
180-
oppositeField.type.reference?.ref === field.$container
181-
) {
182-
// found an opposite relation field that points back to this field's type
183-
return true;
178+
// find the opposite relation with the matching name
179+
const relAttr = oppositeField.attributes.find((a) => a.decl.ref?.name === '@relation');
180+
if (relAttr) {
181+
const relNameExpr = relAttr.args.find((a) => !a.name || a.name === 'name');
182+
const relName = getLiteral<string>(relNameExpr?.value);
183+
if (relName === relationName && oppositeField.type.reference?.ref === field.$container) {
184+
// found an opposite relation field that points back to this field's type
185+
return true;
186+
}
184187
}
185188
}
186189
}
@@ -253,13 +256,15 @@ export default class DataModelValidator implements AstValidator<DataModel> {
253256
relationOwner = field;
254257
}
255258
} else {
256-
[field, oppositeField].forEach((f) =>
257-
accept(
258-
'error',
259-
'Field for one side of relation must carry @relation attribute with both "fields" and "references" fields',
260-
{ node: f }
261-
)
262-
);
259+
[field, oppositeField].forEach((f) => {
260+
if (!this.isSelfRelation(f, thisRelation.name)) {
261+
accept(
262+
'error',
263+
'Field for one side of relation must carry @relation attribute with both "fields" and "references" fields',
264+
{ node: f }
265+
);
266+
}
267+
});
263268
return;
264269
}
265270

packages/schema/src/plugins/prisma/prisma-builder.ts

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ export class Generator {
8080
}
8181

8282
export class DeclarationBase {
83-
public documentations: string[] = [];
83+
constructor(public documentations: string[] = []) {}
8484

8585
addComment(name: string): string {
8686
this.documentations.push(name);
@@ -91,26 +91,38 @@ export class DeclarationBase {
9191
return this.documentations.map((x) => `${x}\n`).join('');
9292
}
9393
}
94-
export class Model extends DeclarationBase {
94+
95+
export class ContainerDeclaration extends DeclarationBase {
96+
constructor(documentations: string[] = [], public attributes: (ContainerAttribute | PassThroughAttribute)[] = []) {
97+
super(documentations);
98+
}
99+
}
100+
101+
export class FieldDeclaration extends DeclarationBase {
102+
constructor(documentations: string[] = [], public attributes: (FieldAttribute | PassThroughAttribute)[] = []) {
103+
super(documentations);
104+
}
105+
}
106+
107+
export class Model extends ContainerDeclaration {
95108
public fields: ModelField[] = [];
96-
public attributes: ModelAttribute[] = [];
97-
constructor(public name: string, public documentations: string[] = []) {
98-
super();
109+
constructor(public name: string, documentations: string[] = []) {
110+
super(documentations);
99111
}
100112

101113
addField(
102114
name: string,
103115
type: ModelFieldType | string,
104-
attributes: FieldAttribute[] = [],
116+
attributes: (FieldAttribute | PassThroughAttribute)[] = [],
105117
documentations: string[] = []
106118
): ModelField {
107119
const field = new ModelField(name, type, attributes, documentations);
108120
this.fields.push(field);
109121
return field;
110122
}
111123

112-
addAttribute(name: string, args: AttributeArg[] = []): ModelAttribute {
113-
const attr = new ModelAttribute(name, args);
124+
addAttribute(name: string, args: AttributeArg[] = []) {
125+
const attr = new ContainerAttribute(name, args);
114126
this.attributes.push(attr);
115127
return attr;
116128
}
@@ -145,14 +157,14 @@ export class ModelFieldType {
145157
}
146158
}
147159

148-
export class ModelField extends DeclarationBase {
160+
export class ModelField extends FieldDeclaration {
149161
constructor(
150162
public name: string,
151163
public type: ModelFieldType | string,
152-
public attributes: FieldAttribute[] = [],
153-
public documentations: string[] = []
164+
attributes: (FieldAttribute | PassThroughAttribute)[] = [],
165+
documentations: string[] = []
154166
) {
155-
super();
167+
super(documentations, attributes);
156168
}
157169

158170
addAttribute(name: string, args: AttributeArg[] = []): FieldAttribute {
@@ -178,14 +190,25 @@ export class FieldAttribute {
178190
}
179191
}
180192

181-
export class ModelAttribute {
193+
export class ContainerAttribute {
182194
constructor(public name: string, public args: AttributeArg[] = []) {}
183195

184196
toString(): string {
185197
return `${this.name}(` + this.args.map((a) => a.toString()).join(', ') + `)`;
186198
}
187199
}
188200

201+
/**
202+
* Represents @@prisma.passthrough and @prisma.passthrough
203+
*/
204+
export class PassThroughAttribute {
205+
constructor(public text: string) {}
206+
207+
toString(): string {
208+
return this.text;
209+
}
210+
}
211+
189212
export class AttributeArg {
190213
constructor(public name: string | undefined, public value: AttributeArgValue) {}
191214

@@ -287,22 +310,25 @@ export class FunctionCallArg {
287310
}
288311
}
289312

290-
export class Enum extends DeclarationBase {
313+
export class Enum extends ContainerDeclaration {
291314
public fields: EnumField[] = [];
292-
public attributes: ModelAttribute[] = [];
293315

294316
constructor(public name: string, public documentations: string[] = []) {
295-
super();
317+
super(documentations);
296318
}
297319

298-
addField(name: string, attributes: FieldAttribute[] = [], documentations: string[] = []): EnumField {
320+
addField(
321+
name: string,
322+
attributes: (FieldAttribute | PassThroughAttribute)[] = [],
323+
documentations: string[] = []
324+
): EnumField {
299325
const field = new EnumField(name, attributes, documentations);
300326
this.fields.push(field);
301327
return field;
302328
}
303329

304-
addAttribute(name: string, args: AttributeArg[] = []): ModelAttribute {
305-
const attr = new ModelAttribute(name, args);
330+
addAttribute(name: string, args: AttributeArg[] = []) {
331+
const attr = new ContainerAttribute(name, args);
306332
this.attributes.push(attr);
307333
return attr;
308334
}
@@ -323,7 +349,11 @@ export class Enum extends DeclarationBase {
323349
}
324350

325351
export class EnumField extends DeclarationBase {
326-
constructor(public name: string, public attributes: FieldAttribute[] = [], public documentations: string[] = []) {
352+
constructor(
353+
public name: string,
354+
public attributes: (FieldAttribute | PassThroughAttribute)[] = [],
355+
public documentations: string[] = []
356+
) {
327357
super();
328358
}
329359

0 commit comments

Comments
 (0)