Skip to content

fix(zmodel): more validation about "view"#526

Merged
ymc9 merged 2 commits intodevfrom
fix/view-check
Dec 23, 2025
Merged

fix(zmodel): more validation about "view"#526
ymc9 merged 2 commits intodevfrom
fix/view-check

Conversation

@ymc9
Copy link
Member

@ymc9 ymc9 commented Dec 23, 2025

Summary by CodeRabbit

  • Improvements

    • Views now disallow @id, @@id, and @@index attributes (clear error messages).
    • Model validation no longer requires unique/id constraints for view definitions.
  • Tests

    • Added view-related schema tests for valid views and error cases for disallowed attributes.
    • Updated e2e test schemas to reflect changes from primary-key to unique constraints in sample views/models.
  • Chores

    • Updated .gitignore to exclude macOS system files (.DS_Store).

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI review requested due to automatic review settings December 23, 2025 03:47
@coderabbitai
Copy link

coderabbitai bot commented Dec 23, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds view-related validation: disallows @id, @@id, and @@index on views; skips unique-criteria requirement for view models. Widens getContainingDataModel parameter type and adds tests; also updates .gitignore to include .DS_Store.

Changes

Cohort / File(s) Summary
Configuration
\.gitignore
Adds .DS_Store to ignored files.
Utilities
packages/language/src/utils.ts
Changes getContainingDataModel parameter type from Expression to AstNode (widened signature only).
Attribute & Model Validators
packages/language/src/validators/attribute-application-validator.ts, packages/language/src/validators/datamodel-validator.ts
Adds checks to error when @id is applied to a view; errors for @@id/@@index/@@unique usages that target view models; skips the non-view unique-criteria enforcement for views. New private _checkId helper added to attribute validator.
Tests
packages/language/test/view.test.ts
New tests for view compilation and negative cases asserting errors for disallowed identity/index attributes.
Repo examples / E2E fixtures
tests/e2e/github-repos/cal.com/schema.ts, tests/e2e/github-repos/cal.com/schema.zmodel
Adjusts field annotations: removes @id/autoincrement from CalVideoSettings.eventTypeId (replaces with @unique); view BookingTimeStatusDenormalized.id changed from @id @unique`` to @unique.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding more validation rules for views in the zmodel schema language, which is reflected across all file changes.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/view-check

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude
Copy link

claude bot commented Dec 23, 2025

Claude finished @ymc9's task —— View job


PR Review: View Validation Enhancements

I've completed my review of the view validation changes. Here's my comprehensive feedback:

Todo List:

  • Read and analyze all changed files
  • Review validation logic implementation
  • Check test coverage and quality
  • Identify potential bugs or issues
  • Assess performance and security considerations
  • Provide comprehensive feedback

Code Quality & Implementation ✅

Strong Points:

  1. Clean, focused changes: The PR makes targeted additions to existing validation infrastructure without disrupting the codebase architecture.

  2. Consistent validation pattern: The implementation follows established patterns using the @check decorator and validator infrastructure.

  3. Type safety improvement: The fix in utils.ts:504 broadens the getContainingDataModel parameter from Expression to AstNode, making it more flexible while maintaining type safety.

  4. Proper separation of concerns: View-specific constraints are appropriately isolated in the attribute validator.

Implementation Details:

attribute-application-validator.ts:297-312

@check('@id')
private _checkId(attr: AttributeApplication, accept: ValidationAcceptor) {
    const dm = getContainingDataModel(attr);
    if (dm?.isView) {
        accept('error', `\`@id\` is not allowed for views`, { node: attr });
    }
}

@check('@@id')
@check('@@index') 
@check('@@unique')
private _checkConstraint(attr: AttributeApplication, accept: ValidationAcceptor) {
    const dm = getContainingDataModel(attr);
    if (dm?.isView && (attr.decl.$refText === '@@id' || attr.decl.$refText === '@@index')) {
        accept('error', `\`${attr.decl.$refText}\` is not allowed for views`, { node: attr });
    }
    // ... rest of existing validation
}

Good: Uses consistent error messaging with backtick formatting
Good: Proper null-safe checks with optional chaining
Good: Reuses existing validation infrastructure

datamodel-validator.ts:53

if (
    !dm.isView &&
    idFields.length === 0 &&
    // ... rest of unique criteria checks
) {

Good: Simple, clear logic - views are exempt from unique criteria requirements


Test Coverage ✅

The test file view.test.ts provides solid coverage:

  1. Positive test: Verifies valid view declarations work
  2. Negative tests: Covers all three forbidden attributes (@id, @@id, @@index)
  3. Error message validation: Ensures correct error messages are displayed

Potential test improvements:

// Consider adding these test cases:
it('allows @@unique on views', async () => {
    await expect(loadSchema(`
        view A {
            x Int
            @@unique([x])
        }
    `)).resolves.toBeTruthy();
});

it('handles views with mixins and inheritance correctly', async () => {
    // Test view-specific validation in inheritance scenarios
});

Potential Issues & Suggestions

Minor Issues:

  1. Missing @@unique test: The PR blocks @@id and @@index on views but allows @@unique. The test suite should include a positive test confirming @@unique is allowed on views.

  2. Syntax error in test: Line 46 and 62 in view.test.ts are missing closing parentheses:

    @@id([id]  // Should be: @@id([id])
    @@index([id]  // Should be: @@index([id])
  3. Consider validation consistency: The validation logic assumes views don't need unique identifiers, but this should be documented as a design decision.

Security & Performance

  • No security concerns: Changes are purely validation logic
  • Performance impact: Minimal - just additional conditional checks during validation
  • No memory leaks: Proper use of existing validation infrastructure

Recommendations

  1. Fix test syntax errors - Add missing closing parentheses
  2. Add @@unique test - Verify unique constraints work on views
  3. Consider documentation - Add comments explaining why views don't need ID constraints

Overall Assessment: APPROVED

This is a well-implemented PR that follows ZenStack's coding standards and architecture. The changes are focused, tested, and maintain backward compatibility. The minor test syntax issues should be fixed before merge.

Files changed: 5 files, +86 lines, -1 line
Risk level: Low
Merge recommendation: Approve after fixing test syntax

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds validation rules to restrict certain attributes on database views in the ZModel schema language. Views are now exempt from requiring unique criteria, and specific attributes (@id, @@id, and @@index) are explicitly disallowed on views.

  • Adds validation to prevent @id, @@id, and @@index attributes on views
  • Exempts views from the requirement to have unique identifier criteria
  • Generalizes the getContainingDataModel utility function to accept any AstNode instead of just Expression

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/language/test/view.test.ts Adds test cases for view validation, including tests to verify that @id, @@id, and @@index are properly rejected on views
packages/language/src/validators/datamodel-validator.ts Adds !dm.isView check to exempt views from requiring unique identifier criteria
packages/language/src/validators/attribute-application-validator.ts Adds validation logic to reject @id, @@id, and @@index attributes on views, and imports getContainingDataModel utility
packages/language/src/utils.ts Generalizes getContainingDataModel function signature from Expression to AstNode parameter type
.gitignore Adds .DS_Store to ignore macOS system files

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b57e58 and 1e5d7ef.

📒 Files selected for processing (5)
  • .gitignore
  • packages/language/src/utils.ts
  • packages/language/src/validators/attribute-application-validator.ts
  • packages/language/src/validators/datamodel-validator.ts
  • packages/language/test/view.test.ts
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects

Applied to files:

  • packages/language/test/view.test.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/**/type*.{ts,tsx} : Ensure TypeScript inference and type coverage are validated through type coverage tests

Applied to files:

  • packages/language/test/view.test.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to **/*.zmodel : ZModel schema files should define database structure and policies that compile to TypeScript via `zenstack generate`

Applied to files:

  • packages/language/test/view.test.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy tests

Applied to files:

  • packages/language/test/view.test.ts
🧬 Code graph analysis (2)
packages/language/src/utils.ts (2)
packages/language/src/ast.ts (3)
  • AstNode (4-4)
  • AstNode (66-71)
  • DataModel (49-54)
packages/language/src/generated/ast.ts (2)
  • DataModel (377-387)
  • DataModel (389-389)
packages/language/src/validators/attribute-application-validator.ts (2)
packages/schema/src/schema.ts (1)
  • AttributeApplication (40-43)
packages/language/src/utils.ts (1)
  • getContainingDataModel (504-513)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Agent
  • GitHub Check: build-test (20.x, postgresql)
  • GitHub Check: build-test (20.x, sqlite)
  • GitHub Check: claude-review
🔇 Additional comments (6)
.gitignore (1)

11-11: LGTM!

Standard addition to ignore macOS system files.

packages/language/src/utils.ts (1)

504-513: LGTM!

Widening the parameter type from Expression to AstNode is appropriate. The traversal logic using $container works correctly for any AST node type, and this enables the function to be used with attribute nodes in the new view validators.

packages/language/src/validators/datamodel-validator.ts (1)

52-58: LGTM!

Correctly exempts views from requiring unique criteria. Views are read-only database constructs that don't need identity constraints.

Consider whether other @id-related validations in validateFields (lines 66-89) could be reached for views. Since @id and @@id are now disallowed on views via attribute-application-validator.ts, those code paths should not be exercised for views, but you may want to add early returns or guards for defensive clarity.

packages/language/src/validators/attribute-application-validator.ts (3)

30-30: LGTM!

Import added for the utility function used in view validation.


297-303: LGTM!

Clean implementation of the field-level @id validation for views.


305-312: LGTM!

The validation correctly allows @@unique on views while disallowing @@id and @@index. This seems intentional since unique constraints can be meaningful for views in a read context.

Please confirm that @@unique should remain allowed on views. The current implementation permits it, which differs from @@id and @@index. If this is intentional, consider adding a test case to document that @@unique is explicitly allowed on views.

@claude
Copy link

claude bot commented Dec 23, 2025

Claude finished @ymc9's task —— View job


Claude finished @ymc9's task —— View job


PR Review: View Validation Enhancements

I've completed my review of the view validation changes. Here's my comprehensive feedback:

Todo List:

  • Read and analyze all changed files
  • Review validation logic implementation
  • Check test coverage and quality
  • Identify potential bugs or issues
  • Assess performance and security considerations
  • Provide comprehensive feedback

Code Quality & Implementation ✅

Strong Points:

  1. Clean, focused changes: The PR makes targeted additions to existing validation infrastructure without disrupting the codebase architecture.

  2. Consistent validation pattern: The implementation follows established patterns using the @check decorator and validator infrastructure.

  3. Type safety improvement: The fix in utils.ts:504 broadens the getContainingDataModel parameter from Expression to AstNode, making it more flexible while maintaining type safety.

  4. Proper separation of concerns: View-specific constraints are appropriately isolated in the attribute validator.

Implementation Details:

attribute-application-validator.ts:297-312

@check('@id')
private _checkId(attr: AttributeApplication, accept: ValidationAcceptor) {
    const dm = getContainingDataModel(attr);
    if (dm?.isView) {
        accept('error', `\`@id\` is not allowed for views`, { node: attr });
    }
}

@check('@@id')
@check('@@index') 
@check('@@unique')
private _checkConstraint(attr: AttributeApplication, accept: ValidationAcceptor) {
    const dm = getContainingDataModel(attr);
    if (dm?.isView && (attr.decl.$refText === '@@id' || attr.decl.$refText === '@@index')) {
        accept('error', `\`${attr.decl.$refText}\` is not allowed for views`, { node: attr });
    }
    // ... rest of existing validation
}

Good: Uses consistent error messaging with backtick formatting
Good: Proper null-safe checks with optional chaining
Good: Reuses existing validation infrastructure

datamodel-validator.ts:53

if (
    !dm.isView &&
    idFields.length === 0 &&
    // ... rest of unique criteria checks
) {

Good: Simple, clear logic - views are exempt from unique criteria requirements


Test Coverage ✅

The test file view.test.ts provides solid coverage:

  1. Positive test: Verifies valid view declarations work
  2. Negative tests: Covers all three forbidden attributes (@id, @@id, @@index)
  3. Positive @@unique test: Correctly validates that @@unique is allowed on views
  4. Error message validation: Uses proper loadSchemaWithError utility

Note: The test implementation is correct - loadSchemaWithError automatically validates that the expected error occurs, so no additional .resolves or .rejects chains are needed.


Potential Issues & Suggestions

Issues Identified:

  1. Test syntax errors (Critical): Lines 46 and 62 in view.test.ts are missing closing parentheses:

    @@id([id]  // Should be: @@id([id])
    @@index([id]  // Should be: @@index([id])

    This will cause parsing errors instead of validation errors, breaking the tests.

  2. Validation consistency: The implementation correctly allows @@unique on views while blocking @@id and @@index. This is a good design decision since unique constraints can be meaningful for views in read contexts.

Recommendations:

  1. Fix test syntax: Add missing closing parentheses in lines 46 and 62
  2. Consider edge cases: The current validation assumes views are properly identified by dm?.isView. This should be robust given the language grammar.

Performance & Security ✅

  • Performance impact: Minimal - just additional conditional checks during validation phase
  • Security concerns: None - changes are purely validation logic with no runtime impact
  • Memory usage: Proper use of existing validation infrastructure, no memory leaks

Architecture Alignment ✅

The changes align well with ZenStack's architecture:

  • Follows established validation patterns
  • Maintains separation between language validation and ORM functionality
  • Consistent with the schema-first, compile-time validation approach

Overall Assessment: APPROVED with minor fixes needed

This is a well-implemented PR that follows ZenStack's coding standards. The validation logic is sound, test coverage is good, and the changes maintain backward compatibility.

Critical Issue: Fix the syntax errors in test lines 46 and 62 before merge.

Files changed: 7 files, +103 lines, -3 lines
Risk level: Low
Merge recommendation: Approve after fixing test syntax errors

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/language/test/view.test.ts (1)

21-68: Missing assertion chains prevent tests from validating errors.

The syntax errors mentioned in previous reviews have been fixed (lines 46 and 62 now have proper closing parentheses). However, the expect() calls still lack assertion chains:

  • Lines 22-35: await expect(loadSchemaWithError(...)) with no .resolves or .rejects
  • Lines 37-51: Same issue
  • Lines 53-67: Same issue

Without chaining a matcher method like .resolves.toBeTruthy() or .rejects.toThrow(), these tests create expectations but don't actually assert anything.

🔎 Proposed fix
     it('does not allow id or index on views', async () => {
         await expect(
             loadSchemaWithError(
                 `
 datasource db {
     provider = 'sqlite'
 }
 
 view A {
     id Int @id
 }
         `,
                 '`@id` is not allowed for views',
             ),
-        );
+        ).resolves.toBeTruthy();
 
         await expect(
             loadSchemaWithError(
                 `
 datasource db {
     provider = 'sqlite'
 }
 
 view A {
     id Int
     @@id([id])
 }
         `,
                 '`@@id` is not allowed for views',
             ),
-        );
+        ).resolves.toBeTruthy();
 
         await expect(
             loadSchemaWithError(
                 `
 datasource db {
     provider = 'sqlite'
 }
 
 view A {
     id Int
     @@index([id])
 }
         `,
                 '`@@index` is not allowed for views',
             ),
-        );
+        ).resolves.toBeTruthy();
     });
🧹 Nitpick comments (1)
tests/e2e/github-repos/cal.com/schema.ts (1)

6559-6666: Align BookingTimeStatusDenormalized.id uniqueness metadata with other unique identifiers

BookingTimeStatusDenormalized.id is now using @unique (good for a view under the new validation rules), but the field itself lacks unique: true, while other single-field uniques in this schema (including views like BookingTimeStatus) typically set both id: true and unique: true and then mirror that in uniqueFields.

If any downstream logic or type-gen relies on the field.unique flag (instead of only scanning attributes/uniqueFields), this model could be treated slightly differently from otherwise-identical views. It’s also a small consistency gap in this generated schema.

Since this file is auto-generated, any adjustment should come from the generator or source schema; conceptually, the field would look like:

Suggested shape for the generated `id` field
-                id: {
-                    name: "id",
-                    type: "Int",
-                    id: true,
-                    attributes: [{ name: "@unique" }]
-                },
+                id: {
+                    name: "id",
+                    type: "Int",
+                    id: true,
+                    unique: true,
+                    attributes: [{ name: "@unique" }]
+                },

Also, because this lives under tests/e2e/github-repos/cal.com/, it’s worth double-checking that the regenerated schema still matches the current cal.com view definition so the e2e compatibility test remains faithful. As per coding guidelines, this e2e fixture should reflect the real upstream schema behavior.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e5d7ef and 1508605.

📒 Files selected for processing (3)
  • packages/language/test/view.test.ts
  • tests/e2e/github-repos/cal.com/schema.ts
  • tests/e2e/github-repos/cal.com/schema.zmodel
🧰 Additional context used
📓 Path-based instructions (2)
**/*.zmodel

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.zmodel: Always run zenstack generate after modifying ZModel schemas
ZModel schema files should define database structure and policies that compile to TypeScript via zenstack generate

Files:

  • tests/e2e/github-repos/cal.com/schema.zmodel
tests/e2e/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

E2E tests should validate real-world schema compatibility with established projects

Files:

  • tests/e2e/github-repos/cal.com/schema.ts
🧠 Learnings (4)
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects

Applied to files:

  • packages/language/test/view.test.ts
  • tests/e2e/github-repos/cal.com/schema.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/**/type*.{ts,tsx} : Ensure TypeScript inference and type coverage are validated through type coverage tests

Applied to files:

  • packages/language/test/view.test.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy tests

Applied to files:

  • packages/language/test/view.test.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to **/*.zmodel : ZModel schema files should define database structure and policies that compile to TypeScript via `zenstack generate`

Applied to files:

  • packages/language/test/view.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build-test (20.x, postgresql)
  • GitHub Check: claude-review
  • GitHub Check: build-test (20.x, sqlite)
🔇 Additional comments (3)
tests/e2e/github-repos/cal.com/schema.zmodel (1)

1650-1650: LGTM! View correctly updated to remove @id.

The change from @id @unique to just @unique aligns with the new validation rules that disallow @id attributes on views. This E2E test ensures the cal.com schema remains compatible with the updated validation.

packages/language/test/view.test.ts (2)

5-19: LGTM! Basic view test is correctly structured.

The test properly validates that a simple view schema compiles successfully, with the correct assertion chain .resolves.toBeTruthy().


70-83: LGTM! @@unique test is correctly structured.

The test properly validates that @@unique is allowed on views, complementing the negative tests for disallowed constructs.

@ymc9 ymc9 merged commit 2432f7f into dev Dec 23, 2025
6 checks passed
@ymc9 ymc9 deleted the fix/view-check branch December 23, 2025 04:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant