From 492dd36292c1b50b2f4dba5e3d43c5e47cccc29c Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Sun, 20 Oct 2024 15:40:45 -0700 Subject: [PATCH 1/3] fix(cli): regular relation fields are incorrectly recognized as self-relation --- .../validator/datamodel-validator.ts | 47 ++++--------------- .../validation/datamodel-validation.test.ts | 4 +- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/packages/schema/src/language-server/validator/datamodel-validator.ts b/packages/schema/src/language-server/validator/datamodel-validator.ts index eb6d06400..ebb014dd1 100644 --- a/packages/schema/src/language-server/validator/datamodel-validator.ts +++ b/packages/schema/src/language-server/validator/datamodel-validator.ts @@ -7,13 +7,7 @@ import { isEnum, isStringLiteral, } from '@zenstackhq/language/ast'; -import { - getLiteral, - getModelFieldsWithBases, - getModelIdFields, - getModelUniqueFields, - isDelegateModel, -} from '@zenstackhq/sdk'; +import { getModelFieldsWithBases, getModelIdFields, getModelUniqueFields, isDelegateModel } from '@zenstackhq/sdk'; import { AstNode, DiagnosticInfo, ValidationAcceptor, getDocument } from 'langium'; import { findUpInheritance } from '../../utils/ast-utils'; import { IssueCodes, SCALAR_TYPES } from '../constants'; @@ -147,15 +141,15 @@ export default class DataModelValidator implements AstValidator { } } + if (!fields && !references) { + return { attr: relAttr, name, fields, references, valid: true }; + } + if (!fields || !references) { - if (this.isSelfRelation(field, name)) { - // self relations are partial - // https://www.prisma.io/docs/concepts/components/prisma-schema/relations/self-relations - } else { - if (accept) { - accept('error', `Both "fields" and "references" must be provided`, { node: relAttr }); - } + if (accept) { + accept('error', `"fields" and "references" must be provided together`, { node: relAttr }); } + // } } else { // validate "fields" and "references" typing consistency if (fields.length !== references.length) { @@ -203,33 +197,12 @@ export default class DataModelValidator implements AstValidator { return { attr: relAttr, name, fields, references, valid }; } - private isSelfRelation(field: DataModelField, relationName?: string) { + private isSelfRelation(field: DataModelField, _relationName?: string) { if (field.type.reference?.ref === field.$container) { // field directly references back to its type return true; } - if (relationName) { - // field's relation points to another type, and that type's opposite relation field - // points back - const oppositeModel = field.type.reference?.ref as DataModel; - if (oppositeModel) { - const oppositeModelFields = getModelFieldsWithBases(oppositeModel); - for (const oppositeField of oppositeModelFields) { - // find the opposite relation with the matching name - const relAttr = oppositeField.attributes.find((a) => a.decl.ref?.name === '@relation'); - if (relAttr) { - const relNameExpr = relAttr.args.find((a) => !a.name || a.name === 'name'); - const relName = getLiteral(relNameExpr?.value); - if (relName === relationName && oppositeField.type.reference?.ref === field.$container) { - // found an opposite relation field that points back to this field's type - return true; - } - } - } - } - } - return false; } @@ -333,7 +306,7 @@ export default class DataModelValidator implements AstValidator { if (!this.isSelfRelation(f, thisRelation.name)) { accept( 'error', - 'Field for one side of relation must carry @relation attribute with both "fields" and "references" fields', + 'Field for one side of relation must carry @relation attribute with both "fields" and "references"', { node: f } ); } diff --git a/packages/schema/tests/schema/validation/datamodel-validation.test.ts b/packages/schema/tests/schema/validation/datamodel-validation.test.ts index e7dd6bf84..d89e96a44 100644 --- a/packages/schema/tests/schema/validation/datamodel-validation.test.ts +++ b/packages/schema/tests/schema/validation/datamodel-validation.test.ts @@ -451,7 +451,7 @@ describe('Data Model Validation Tests', () => { aId String } `) - ).toMatchObject(errorLike(`Both "fields" and "references" must be provided`)); + ).toMatchObject(errorLike(`"fields" and "references" must be provided together`)); // one-to-one inconsistent attribute expect( @@ -541,7 +541,7 @@ describe('Data Model Validation Tests', () => { `) ).toMatchObject( errorLike( - `Field for one side of relation must carry @relation attribute with both "fields" and "references" fields` + `Field for one side of relation must carry @relation attribute with both "fields" and "references"` ) ); From 93e61501389e368ca15ef91d04fe7dcde8298648 Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Sun, 20 Oct 2024 15:50:06 -0700 Subject: [PATCH 2/3] update --- .../src/language-server/validator/datamodel-validator.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/schema/src/language-server/validator/datamodel-validator.ts b/packages/schema/src/language-server/validator/datamodel-validator.ts index ebb014dd1..e826e6254 100644 --- a/packages/schema/src/language-server/validator/datamodel-validator.ts +++ b/packages/schema/src/language-server/validator/datamodel-validator.ts @@ -197,13 +197,8 @@ export default class DataModelValidator implements AstValidator { return { attr: relAttr, name, fields, references, valid }; } - private isSelfRelation(field: DataModelField, _relationName?: string) { - if (field.type.reference?.ref === field.$container) { - // field directly references back to its type - return true; - } - - return false; + private isSelfRelation(field: DataModelField) { + return field.type.reference?.ref === field.$container; } private validateRelationField(contextModel: DataModel, field: DataModelField, accept: ValidationAcceptor) { From 10c2f7b8769e90bbc70fd89b627995c4d7223f7f Mon Sep 17 00:00:00 2001 From: ymc9 <104139426+ymc9@users.noreply.github.com> Date: Sun, 20 Oct 2024 16:29:47 -0700 Subject: [PATCH 3/3] fix build --- .../schema/src/language-server/validator/datamodel-validator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/schema/src/language-server/validator/datamodel-validator.ts b/packages/schema/src/language-server/validator/datamodel-validator.ts index e826e6254..6b27d2f9a 100644 --- a/packages/schema/src/language-server/validator/datamodel-validator.ts +++ b/packages/schema/src/language-server/validator/datamodel-validator.ts @@ -298,7 +298,7 @@ export default class DataModelValidator implements AstValidator { // if both the field is array, then it's an implicit many-to-many relation if (!(field.type.array && oppositeField.type.array)) { [field, oppositeField].forEach((f) => { - if (!this.isSelfRelation(f, thisRelation.name)) { + if (!this.isSelfRelation(f)) { accept( 'error', 'Field for one side of relation must carry @relation attribute with both "fields" and "references"',