Skip to content

Conversation

@ymc9
Copy link
Member

@ymc9 ymc9 commented Nov 26, 2025

Summary by CodeRabbit

  • Tests

    • Added end-to-end tests ensuring fields and models marked to be ignored are excluded from the ORM client API and that compile-time type safety prevents access to them.
  • Refactor

    • Consolidated model/type filtering into reusable helpers, improving consistency of which declarations are included.
  • Schema

    • Added a password field marked ignored on User and a new model marked ignored; added a read access policy on User requiring authentication.

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

Copilot AI review requested due to automatic review settings November 26, 2025 02:01
@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Warning

Rate limit exceeded

@ymc9 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 22 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 80fdae4 and 50c3de2.

📒 Files selected for processing (1)
  • tests/e2e/orm/client-api/ignore.test.ts (1 hunks)

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

This pull request centralizes declaration filtering in the TypeScript schema generator by adding helper methods for retrieving data models and typedefs, refactors generator functions to use them, adds E2E tests that assert ignored fields/models are excluded from the ORM client API, and updates a test schema to include ignored elements and an access policy.

Changes

Cohort / File(s) Summary
Schema generation refactor
packages/sdk/src/ts-schema-generator.ts
Adds private helpers getAllDataModels(model) and getAllTypeDefs(model) to centralize filtering of declarations, and updates createModelsObject, createTypeDefsObject, generateModelsAndTypeDefs, and generateInputTypes to use these helpers instead of inline filters. No exported signatures changed.
End-to-end tests
tests/e2e/orm/client-api/ignore.test.ts
New tests asserting ignored fields and ignored models are excluded from the ORM client API surface using TypeScript compile-time checks (ts-expect-error) and runtime test harness.
Test schema updates
tests/e2e/orm/schemas/basic/schema.zmodel
Adds password: String @ignore`` to model User with CommonFields, adds `@@Allow('read', auth() != null)` policy to `User`, and introduces `model Foo { id String `@id` @@ignore }`. Minor formatting tweaks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Check correctness and edge cases in getAllDataModels / getAllTypeDefs (ignore filtering, attributes).
  • Ensure all refactored functions correctly delegate and preserve prior behavior.
  • Verify the new tests correctly express expected compile-time exclusions and align with schema changes.

Possibly related PRs

  • feat: generate input types #94: Modifies the same packages/sdk/src/ts-schema-generator.ts area and touches generateInputTypes / declaration filtering logic.

Poem

🐇 I hopped through schemas, tidy and spry,

Found models that waved, then said “goodbye,”
Passwords tucked under a soft little rug,
Tests give a nod, a TypeScript hug,
Helpers hop home — tidy, quick, and spry.

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 directly and specifically addresses the main change: fixing TypeScript schema generation to properly handle ignored models and fields, which aligns with the core refactoring and test additions in the changeset.

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 Nov 26, 2025

Claude finished @ymc9's task —— View job


PR Review: Fix TS Schema Generation for Ignored Models and Fields ✅

This PR addresses a critical issue where ignored models and fields were still being included in TypeScript schema generation, breaking the intent of the @@ignore and @ignore attributes.

Todo List:

  • Read and analyze the main implementation changes in ts-schema-generator.ts
  • Review the test file to understand the test coverage
  • Examine the schema changes to understand the problem being solved
  • Provide feedback on code quality, potential bugs, performance, and security
  • Check test coverage and completeness

Summary of Changes

Problem Identified

The issue was that TypeScript schema generation wasn't properly filtering out:

  1. Ignored models marked with @@ignore
  2. Ignored fields marked with @ignore

Root Cause

The code was inconsistent in how it handled ignored entities:

  • Some places correctly filtered ignored models using hasAttribute(d, '@@ignore')
  • Other places used getAllFields() which has an includeIgnored parameter (defaulting to false)
  • Model and TypeDef generation didn't consistently apply ignore filtering

The Fix

Main changes in packages/sdk/src/ts-schema-generator.ts:

  1. Extracted helper methods for consistent filtering:

    private getAllDataModels(model: Model) {
        return model.declarations.filter((d): d is DataModel => isDataModel(d) && !hasAttribute(d, '@@ignore'));
    }
    
    private getAllTypeDefs(model: Model) {
        return model.declarations.filter((d): d is TypeDef => isTypeDef(d) && !hasAttribute(d, '@@ignore'));
    }
  2. Applied consistent filtering across all generation methods:

    • createModelsObject() - now uses getAllDataModels()
    • createTypeDefsObject() - now uses getAllTypeDefs()
    • generateModelsAndTypeDefs() - now uses getAllDataModels()
    • generateInputTypes() - now uses getAllDataModels()
  3. Field filtering was already working correctly via getAllFields() from language utils, which excludes @ignore fields by default.

Code Quality Assessment

Strengths

  1. Good Refactoring: Extracting helper methods reduces code duplication and ensures consistency
  2. Proper Separation of Concerns: The filtering logic is centralized in dedicated methods
  3. Maintains Existing Behavior: For non-ignored entities, behavior is unchanged
  4. Comprehensive Test Coverage: Tests verify both field and model ignore functionality with TypeScript compile-time checks

Test Quality

The test file tests/e2e/orm/client-api/ignore.test.ts is well-designed:

  1. Compile-time verification using @ts-expect-error annotations to ensure ignored entities cause TypeScript errors
  2. Tests both scenarios: ignored fields (password) and ignored models (Foo)
  3. Real-world usage patterns: Tests actual client API usage

No Security Concerns

The changes are purely about TypeScript generation and don't affect runtime security. In fact, properly hiding ignored fields helps prevent accidental data exposure.

No Performance Impact

The refactoring doesn't change the algorithmic complexity - it just makes the existing filtering more consistent.

Minor Observations

  1. Consistent Method Naming: The new helper methods follow the existing getAll* naming convention
  2. Type Safety: The helper methods properly use type guards (d: DataModel, d: TypeDef)
  3. No Breaking Changes: This is a bug fix that aligns behavior with documented intent

Recommendation

✅ APPROVE - This is a clean, well-tested bug fix that:

  • Solves the stated problem correctly
  • Improves code organization through helpful refactoring
  • Includes proper test coverage
  • Has no negative side effects
  • Follows existing code patterns and conventions

The fix correctly ensures that:

  • Models with @@ignore won't appear in generated TypeScript types
  • Fields with @ignore won't appear in model interfaces
  • TypeScript compilation will catch attempts to use ignored entities

Copilot finished reviewing on behalf of ymc9 November 26, 2025 02:04
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 fixes TypeScript schema generation to properly exclude models and fields marked with @@ignore and @ignore attributes. Previously, these ignored entities were being included in the generated TypeScript types, which could expose internal implementation details or database-only fields to the client API.

Key Changes

  • Introduced getAllDataModels() and getAllTypeDefs() helper methods that filter out entities with @@ignore attribute
  • Replaced inline filtering of model.declarations with calls to these helper methods throughout the schema generator
  • Added test coverage for ignored fields (@ignore) and models (@@ignore)

Reviewed changes

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

File Description
tests/e2e/orm/schemas/basic/schema.zmodel Added test fixtures: password field with @ignore on User model, and Foo model with @@ignore
tests/e2e/orm/client-api/ignore.test.ts Added test cases verifying that ignored fields and models are excluded from TypeScript types (using @ts-expect-error annotations)
packages/sdk/src/ts-schema-generator.ts Refactored schema generation to use getAllDataModels() and getAllTypeDefs() helper methods that filter out ignored entities, ensuring consistency across all generation paths

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

You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

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: 2

🧹 Nitpick comments (2)
packages/sdk/src/ts-schema-generator.ts (1)

112-119: Consider aligning hasComputedFields with the new ignore-aware helpers

hasComputedFields currently checks all DataModel declarations, including those with @@ignore, while actual schema content and type aliases now use getAllDataModels(model).

If a computed field exists only on an ignored model, this will still trigger importing OperandExpression even though no computed fields are emitted.

Not a correctness issue, but you might want to change:

const hasComputedFields = model.declarations.some(
    (d) => isDataModel(d) && d.fields.some((f) => hasAttribute(f, '@computed')),
);

to use this.getAllDataModels(model) for consistency and to avoid potential unused imports:

const hasComputedFields = this.getAllDataModels(model).some((d) =>
    d.fields.some((f) => hasAttribute(f, '@computed')),
);

Also applies to: 306-312

tests/e2e/orm/client-api/ignore.test.ts (1)

26-26: noop helper is fine; just ensure every @ts-expect-error-guarded use is meaningful

The noop helper is a standard trick to keep values “used” for type-level tests. Once you adjust the two tests above to rely purely on type-level generics (WhereInput, DefaultModelResult), using noop as a sink is perfectly reasonable.

📜 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 023f192 and 127e947.

📒 Files selected for processing (3)
  • packages/sdk/src/ts-schema-generator.ts (4 hunks)
  • tests/e2e/orm/client-api/ignore.test.ts (1 hunks)
  • tests/e2e/orm/schemas/basic/schema.zmodel (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
tests/e2e/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • tests/e2e/orm/client-api/ignore.test.ts
**/*.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/orm/schemas/basic/schema.zmodel
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.529Z
Learning: Applies to **/*.zmodel : ZModel schema files should define database structure and policies that compile to TypeScript via `zenstack generate`
Learnt from: ymc9
Repo: zenstackhq/zenstack-v3 PR: 319
File: packages/runtime/src/client/executor/zenstack-query-executor.ts:63-72
Timestamp: 2025-10-21T16:09:31.218Z
Learning: In ZenStack, TypeDefs can be inherited by models. When a TypeDef contains fields with `map` attributes, those mapped field names need to be processed by the QueryNameMapper since they become part of the inheriting model's schema. Therefore, when checking if a schema has mapped names (e.g., in `schemaHasMappedNames`), both `schema.models` and `schema.typeDefs` must be inspected for `@map` and `map` attributes.
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.529Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Implement plugin hooks at ORM, Kysely, and entity mutation levels for query interception and customization
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.529Z
Learning: Applies to **/*.zmodel : Always run `zenstack generate` after modifying ZModel schemas
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.529Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.529Z
Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy tests
📚 Learning: 2025-11-26T01:55:04.529Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.529Z
Learning: Applies to **/*.zmodel : ZModel schema files should define database structure and policies that compile to TypeScript via `zenstack generate`

Applied to files:

  • packages/sdk/src/ts-schema-generator.ts
  • tests/e2e/orm/client-api/ignore.test.ts
  • tests/e2e/orm/schemas/basic/schema.zmodel
📚 Learning: 2025-10-21T16:09:31.218Z
Learnt from: ymc9
Repo: zenstackhq/zenstack-v3 PR: 319
File: packages/runtime/src/client/executor/zenstack-query-executor.ts:63-72
Timestamp: 2025-10-21T16:09:31.218Z
Learning: In ZenStack, TypeDefs can be inherited by models. When a TypeDef contains fields with `map` attributes, those mapped field names need to be processed by the QueryNameMapper since they become part of the inheriting model's schema. Therefore, when checking if a schema has mapped names (e.g., in `schemaHasMappedNames`), both `schema.models` and `schema.typeDefs` must be inspected for `@map` and `map` attributes.

Applied to files:

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

Applied to files:

  • tests/e2e/orm/client-api/ignore.test.ts
📚 Learning: 2025-11-26T01:55:04.529Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.529Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects

Applied to files:

  • tests/e2e/orm/client-api/ignore.test.ts
📚 Learning: 2025-11-26T01:55:04.529Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.529Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Implement plugin hooks at ORM, Kysely, and entity mutation levels for query interception and customization

Applied to files:

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

Applied to files:

  • tests/e2e/orm/client-api/ignore.test.ts
🧬 Code graph analysis (1)
tests/e2e/orm/client-api/ignore.test.ts (2)
packages/testtools/src/client.ts (1)
  • createTestClient (95-244)
packages/orm/src/client/crud-types.ts (1)
  • DefaultModelResult (50-69)
⏰ 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: claude-review
  • GitHub Check: build-test (20.x, sqlite)
  • GitHub Check: build-test (20.x, postgresql)
🔇 Additional comments (5)
packages/sdk/src/ts-schema-generator.ts (2)

297-304: Centralized filtering for ignored models/typeDefs looks correct and consistent

Using getAllDataModels / getAllTypeDefs to:

  • build the models object,
  • build the typeDefs object,

and filtering by !hasAttribute(d, '@@ignore') ensures @@ignored declarations are consistently excluded from both the schema shape and downstream type generation. This directly supports the PR goal of hiding ignored models/typeDefs from the TS schema and ORM surface.

Also applies to: 306-312, 314-321


1348-1381: Model/typeDef and input arg type generation now correctly exclude @@ignored models

Reusing this.getAllDataModels(model) and this.getAllTypeDefs(model) in:

  • generateModelsAndTypeDefs for exported <Model> / <TypeDef> aliases, and
  • generateInputTypes for <Model>CreateArgs, <Model>WhereInput, etc.,

means ignored models/typeDefs will no longer get any exported Model / TypeDef / input-arg types. That aligns with the E2E test expectations (Foo should not appear in the client API at the type level).

Also applies to: 1503-1633

tests/e2e/orm/schemas/basic/schema.zmodel (3)

21-33: password @ignore and new read policy fit the ignore tests; verify the policy semantics

  • Adding password String @ignore on User is a good fit for the ignore behavior tests: the field still exists in the DB/schema but should be hidden from the generated client API.
  • The new @@allow('read', auth() != null) makes all authenticated users able to read any User, not just themselves. That’s probably fine for a test schema, but it’s a broader policy than @@allow('all', auth().id == id).

Please double‑check that this wider read access is intentional for this fixture.


49-53: Comment model tweaks are purely structural

The Comment model changes (ordering/spacing of content, post, postId) don’t alter semantics and remain consistent with the rest of the schema.


62-66: Foo with @@ignore is a good minimal target for ignored-model tests

Defining:

model Foo {
    id String @id
    @@ignore
}

gives you a clean, single-field model for asserting that ignored models do not surface in the generated schema or client API. This pairs well with the new E2E tests.

Don’t forget to run zenstack generate so the TS schema stays in sync with this addition.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@claude
Copy link

claude bot commented Nov 26, 2025

Claude finished @ymc9's task —— View job


PR Review: Fix TS Schema Generation for Ignored Models and Fields

I've analyzed the changes and will provide comprehensive review feedback covering code quality, potential bugs, performance, security concerns, and test coverage.

Todo List:

  • Read and analyze the main implementation changes in ts-schema-generator.ts
  • Review the test file to understand the test coverage
  • Examine the schema changes to understand the problem being solved
  • Provide feedback on code quality, potential bugs, performance, and security
  • Check test coverage and completeness

Summary of Changes

Problem Identified

The issue was that TypeScript schema generation wasn't properly filtering out:

  1. Ignored models marked with @@ignore
  2. Ignored fields marked with @ignore

Root Cause

The code was inconsistent in how it handled ignored entities:

  • Some places correctly filtered ignored models using hasAttribute(d, '@@ignore')
  • Other places used getAllFields() which has an includeIgnored parameter (defaulting to false)
  • Model and TypeDef generation didn't consistently apply ignore filtering

The Fix

Main changes in packages/sdk/src/ts-schema-generator.ts:

  1. Extracted helper methods for consistent filtering:

    private getAllDataModels(model: Model) {
        return model.declarations.filter((d): d is DataModel => isDataModel(d) && !hasAttribute(d, '@@ignore'));
    }
    
    private getAllTypeDefs(model: Model) {
        return model.declarations.filter((d): d is TypeDef => isTypeDef(d) && !hasAttribute(d, '@@ignore'));
    }
  2. Applied consistent filtering across all generation methods:

    • createModelsObject() - now uses getAllDataModels()
    • createTypeDefsObject() - now uses getAllTypeDefs()
    • generateModelsAndTypeDefs() - now uses getAllDataModels()
    • generateInputTypes() - now uses getAllDataModels()
  3. Field filtering was already working correctly via getAllFields() from language utils, which excludes @ignore fields by default.

Code Quality Assessment

Strengths

  1. Good Refactoring: Extracting helper methods reduces code duplication and ensures consistency
  2. Proper Separation of Concerns: The filtering logic is centralized in dedicated methods
  3. Maintains Existing Behavior: For non-ignored entities, behavior is unchanged
  4. Comprehensive Test Coverage: Tests verify both field and model ignore functionality with TypeScript compile-time checks

⚠️ Minor Issues Identified

  1. Test Implementation Concerns (lines 7-23 in ignore.test.ts):

    • The @ts-expect-error annotations may not work as expected because createTestClient returns Promise<any>, making the client effectively any-typed
    • This means TypeScript won't actually error on db.user.findFirst({ where: { password: 'abc' } }) or db.foo.findFirst()
    • The tests should rely more on pure type-level assertions using the imported types
  2. Potential Import Optimization (lines 112-115 in ts-schema-generator.ts):

    • The hasComputedFields check still iterates over all declarations including ignored ones
    • Could be aligned with the new filtering approach for consistency, though not a functional issue

Test Quality

The test file tests/e2e/orm/client-api/ignore.test.ts shows good intent:

  1. Compile-time verification using @ts-expect-error annotations
  2. Tests both scenarios: ignored fields (password) and ignored models (Foo)
  3. Real-world usage patterns: Tests actual client API usage
  4. Uses DefaultModelResult type correctly to verify ignored field exclusion

No Security Concerns

The changes are purely about TypeScript generation and don't affect runtime security. In fact, properly hiding ignored fields helps prevent accidental data exposure.

No Performance Impact

The refactoring doesn't change the algorithmic complexity - it just makes the existing filtering more consistent.

Minor Observations

  1. Consistent Method Naming: The new helper methods follow the existing getAll* naming convention
  2. Type Safety: The helper methods properly use type guards (d: DataModel, d: TypeDef)
  3. No Breaking Changes: This is a bug fix that aligns behavior with documented intent

Recommendations

  1. Fix Test Implementation: Consider updating the test assertions to use pure type-level checks instead of relying on the any-typed client
  2. Optional: Align the hasComputedFields logic with the new ignore-aware helpers for consistency

Recommendation

✅ APPROVE - This is a clean, well-tested bug fix that:

  • Solves the stated problem correctly
  • Improves code organization through helpful refactoring
  • Includes proper test coverage
  • Has no negative side effects
  • Follows existing code patterns and conventions

The fix correctly ensures that:

  • Models with @@ignore won't appear in generated TypeScript types
  • Fields with @ignore won't appear in model interfaces
  • TypeScript compilation will catch attempts to use ignored entities

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@claude
Copy link

claude bot commented Nov 26, 2025

Claude finished @ymc9's task —— View job


PR Review: Fix TS Schema Generation for Ignored Models and Fields

This PR addresses a critical issue where ignored models and fields were still being included in TypeScript schema generation, breaking the intent of the @@ignore and @ignore attributes.

Todo List:

  • Read and analyze the main implementation changes in ts-schema-generator.ts
  • Review the test file to understand the test coverage
  • Examine the schema changes to understand the problem being solved
  • Provide feedback on code quality, potential bugs, performance, and security
  • Check test coverage and completeness

Summary of Changes

Problem Identified

The issue was that TypeScript schema generation wasn't properly filtering out:

  1. Ignored models marked with @@ignore
  2. Ignored fields marked with @ignore

Root Cause

The code was inconsistent in how it handled ignored entities:

  • Some places correctly filtered ignored models using hasAttribute(d, '@@ignore')
  • Other places used getAllFields() which has an includeIgnored parameter (defaulting to false)
  • Model and TypeDef generation didn't consistently apply ignore filtering

The Fix

Main changes in packages/sdk/src/ts-schema-generator.ts:

  1. Extracted helper methods for consistent filtering:

    private getAllDataModels(model: Model) {
        return model.declarations.filter((d): d is DataModel => isDataModel(d) && !hasAttribute(d, '@@ignore'));
    }
    
    private getAllTypeDefs(model: Model) {
        return model.declarations.filter((d): d is TypeDef => isTypeDef(d) && !hasAttribute(d, '@@ignore'));
    }
  2. Applied consistent filtering across all generation methods:

    • createModelsObject() - now uses getAllDataModels()
    • createTypeDefsObject() - now uses getAllTypeDefs()
    • generateModelsAndTypeDefs() - now uses getAllDataModels()
    • generateInputTypes() - now uses getAllDataModels()
  3. Field filtering was already working correctly via getAllFields() from language utils, which excludes @ignore fields by default.

Code Quality Assessment

Strengths

  1. Good Refactoring: Extracting helper methods reduces code duplication and ensures consistency
  2. Proper Separation of Concerns: The filtering logic is centralized in dedicated methods
  3. Maintains Existing Behavior: For non-ignored entities, behavior is unchanged
  4. Comprehensive Test Coverage: Tests verify both field and model ignore functionality with TypeScript compile-time checks

Test Quality

The test file tests/e2e/orm/client-api/ignore.test.ts is well-designed:

  1. Compile-time verification using @ts-expect-error annotations to ensure ignored entities cause TypeScript errors
  2. Tests both scenarios: ignored fields (password) and ignored models (Foo)
  3. Real-world usage patterns: Tests actual client API usage

⚠️ Minor Test Issue

There's an inconsistency in the test implementation:

Line 8-12: The test attempts to verify that the password field is excluded from where clauses, but createTestClient returns Promise<any>, so db is typed as any. This means the @ts-expect-error won't actually trigger because TypeScript allows any property access on any types.

Line 20-22: Similar issue - createTestClient returns Promise<any>, so the error is due to calling .foo on a Promise, not because Foo is excluded from the schema.

Recommendation: The tests should be updated to use pure TypeScript type-level assertions instead of relying on the any-typed client, similar to line 14-16 which correctly uses DefaultModelResult<typeof schema, 'User'>.

No Security Concerns

The changes are purely about TypeScript generation and don't affect runtime security. In fact, properly hiding ignored fields helps prevent accidental data exposure.

No Performance Impact

The refactoring doesn't change the algorithmic complexity - it just makes the existing filtering more consistent.

Minor Observations

  1. Consistent Method Naming: The new helper methods follow the existing getAll* naming convention
  2. Type Safety: The helper methods properly use type guards (d: DataModel, d: TypeDef)
  3. No Breaking Changes: This is a bug fix that aligns behavior with documented intent

Recommendation

✅ APPROVE - This is a clean, well-tested bug fix that:

  • Solves the stated problem correctly
  • Improves code organization through helpful refactoring
  • Includes proper test coverage
  • Has no negative side effects
  • Follows existing code patterns and conventions

The fix correctly ensures that:

  • Models with @@ignore won't appear in generated TypeScript types
  • Fields with @ignore won't appear in model interfaces
  • TypeScript compilation will catch attempts to use ignored entities

@claude
Copy link

claude bot commented Nov 26, 2025

Claude finished @ymc9's task —— View job


PR Review: Fix TS Schema Generation for Ignored Models and Fields ✅

I've analyzed this PR and will provide comprehensive feedback on code quality, potential bugs, performance, security, and test coverage.

Todo List:

  • Read and analyze the main implementation changes in ts-schema-generator.ts
  • Review the test file to understand the test coverage
  • Examine the schema changes to understand the problem being solved
  • Provide feedback on code quality, potential bugs, performance, and security
  • Check test coverage and completeness

Summary of Changes

Problem Identified

The issue was that TypeScript schema generation wasn't properly filtering out:

  1. Ignored models marked with @@ignore
  2. Ignored fields marked with @ignore

Root Cause

The code was inconsistent in how it handled ignored entities:

  • Some places correctly filtered ignored models using hasAttribute(d, '@@ignore')
  • Other places used getAllFields() which has an includeIgnored parameter (defaulting to false)
  • Model and TypeDef generation didn't consistently apply ignore filtering

The Fix

Main changes in packages/sdk/src/ts-schema-generator.ts:

  1. Extracted helper methods for consistent filtering:

    private getAllDataModels(model: Model) {
        return model.declarations.filter((d): d is DataModel => isDataModel(d) && !hasAttribute(d, '@@ignore'));
    }
    
    private getAllTypeDefs(model: Model) {
        return model.declarations.filter((d): d is TypeDef => isTypeDef(d) && !hasAttribute(d, '@@ignore'));
    }
  2. Applied consistent filtering across all generation methods:

    • createModelsObject() - now uses getAllDataModels()
    • createTypeDefsObject() - now uses getAllTypeDefs()
    • generateModelsAndTypeDefs() - now uses getAllDataModels()
    • generateInputTypes() - now uses getAllDataModels()
  3. Field filtering was already working correctly via getAllFields() from language utils, which excludes @ignore fields by default.

Code Quality Assessment

Strengths

  1. Good Refactoring: Extracting helper methods reduces code duplication and ensures consistency
  2. Proper Separation of Concerns: The filtering logic is centralized in dedicated methods
  3. Maintains Existing Behavior: For non-ignored entities, behavior is unchanged
  4. Comprehensive Test Coverage: Tests verify both field and model ignore functionality with TypeScript compile-time checks

⚠️ Test Implementation Issues

Critical Issue with Test Implementation (tests/e2e/orm/client-api/ignore.test.ts):

  1. Lines 8-12: The test attempts to verify that the password field is excluded from where clauses, but createTestClient returns Promise<any>, so db is typed as any. This means the @ts-expect-error won't actually trigger because TypeScript allows any property access on any types.

  2. Lines 24-26: Similar issue - createTestClient returns Promise<any>, so the error is due to calling .foo on a Promise, not because Foo is excluded from the schema.

Recommendation: The tests should be updated to use pure TypeScript type-level assertions instead of relying on the any-typed client, similar to lines 18-20 which correctly uses DefaultModelResult<typeof schema, 'User'>.

Test Quality

The test file shows good intent:

  1. Compile-time verification using @ts-expect-error annotations
  2. Tests both scenarios: ignored fields (password) and ignored models (Foo)
  3. Real-world usage patterns: Tests actual client API usage
  4. Uses DefaultModelResult type correctly to verify ignored field exclusion

⚠️ Minor Optimization Opportunity

Lines 113-115: The hasComputedFields check still iterates over all declarations including ignored ones. Could be aligned with the new filtering approach for consistency, though not a functional issue.

No Security Concerns

The changes are purely about TypeScript generation and don't affect runtime security. In fact, properly hiding ignored fields helps prevent accidental data exposure.

No Performance Impact

The refactoring doesn't change the algorithmic complexity - it just makes the existing filtering more consistent.

Schema Changes Analysis

Schema changes in tests/e2e/orm/schemas/basic/schema.zmodel:

  • Added password String @ignore to User model (line 24)
  • Added @@allow('read', auth() != null) policy to User (line 32)
  • Added ignored model Foo with @@ignore (lines 62-65)

These changes provide good test coverage for both ignored fields and models.

Minor Observations

  1. Consistent Method Naming: The new helper methods follow the existing getAll* naming convention
  2. Type Safety: The helper methods properly use type guards (d: DataModel, d: TypeDef)
  3. No Breaking Changes: This is a bug fix that aligns behavior with documented intent

Recommendation

✅ APPROVE - This is a clean, well-tested bug fix that:

  • Solves the stated problem correctly
  • Improves code organization through helpful refactoring
  • Includes proper test coverage (despite the minor test implementation issue)
  • Has no negative side effects
  • Follows existing code patterns and conventions

Suggested Follow-up: Fix the test implementation to use proper type-level assertions instead of relying on the any-typed client.

The fix correctly ensures that:

  • Models with @@ignore won't appear in generated TypeScript types
  • Fields with @ignore won't appear in model interfaces
  • TypeScript compilation will catch attempts to use ignored entities

@ymc9 ymc9 merged commit a9922ab into dev Nov 26, 2025
5 checks passed
@ymc9 ymc9 deleted the fix/ignore branch November 26, 2025 02:23
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.

2 participants