Skip to content

fix(orm): exclude Unsupported fields from ORM client#2468

Merged
ymc9 merged 8 commits intodevfrom
fix/exclude-unsupported-fields
Mar 17, 2026
Merged

fix(orm): exclude Unsupported fields from ORM client#2468
ymc9 merged 8 commits intodevfrom
fix/exclude-unsupported-fields

Conversation

@ymc9
Copy link
Copy Markdown
Member

@ymc9 ymc9 commented Mar 9, 2026

Summary

  • Exclude Unsupported type fields from all ORM client TypeScript types (result, where, select, omit, orderBy, create, update, distinct, aggregate, groupBy)
  • Skip Unsupported fields in Zod validation schemas, SQL SELECT queries, and schema pusher
  • Disable create/upsert operations (both type-level and runtime) for models with required Unsupported fields that have no default value
  • Add shared isUnsupportedField helper in query-utils.ts and FieldIsUnsupported/ModelHasRequiredUnsupportedField type utilities in schema.ts

Test plan

  • 9 type-level tests verifying Unsupported fields are excluded from all args/result types
  • 12 Zod schema tests verifying Unsupported fields are rejected in all schema types
  • 9 ORM call tests (PostgreSQL) verifying runtime behavior end-to-end
  • Existing regression tests pass (issue-1870, issue-2246, computed-fields, delegate)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Support for unsupported database field types (e.g., PostgreSQL XML) with automatic exclusion from query/select/create payloads and Zod validation.
    • Models with unsupported required fields are detected so creation-related operations are conditionally disabled.
  • Bug Fixes

    • Corrected operation availability and typings so write operations are blocked when fields are unsupported and required.
  • Tests

    • Added extensive end-to-end tests validating typing and runtime validation for unsupported-field behavior across operations.

Unsupported fields (e.g., Unsupported("xml")) are database-specific types
that cannot be meaningfully read or written through the ORM. This change
excludes them from TypeScript types, Zod validation schemas, and SQL
queries. Models with required Unsupported fields (no default) have their
create/upsert operations disabled since values cannot be provided.

- Add FieldIsUnsupported and ModelHasRequiredUnsupportedField type utils
- Exclude Unsupported fields from result, where, select, omit, orderBy,
  create, update, distinct, aggregate, and groupBy types
- Skip Unsupported fields in all Zod schema generation
- Skip Unsupported fields in SELECT queries and schema pusher
- Disable create/upsert operations for models with required Unsupported
  fields (both at type level and runtime)
- Add isUnsupportedField shared helper in query-utils
- Add comprehensive type tests, Zod tests, and ORM call tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 9, 2026

Claude finished @ymc9's task —— View job


PR Review: Exclude Unsupported Fields from ORM Client

This is a well-architected and comprehensive solution for handling Unsupported field types in the ZenStack ORM. The implementation consistently excludes Unsupported fields from all client operations while providing intelligent runtime safeguards.

Code Quality Assessment

✅ Excellent Type Safety:

  • Strong Type Utilities: The FieldIsUnsupported<Schema, Model, Field> and ModelHasRequiredUnsupportedField<Schema, Model> type utilities in packages/schema/src/schema.ts:289-297 and packages/orm/src/client/type-utils.ts:10-25 provide robust compile-time exclusion
  • Consistent Field Exclusion: GetModelFields type properly filters out unsupported fields across all contexts
  • Smart Operation Blocking: Models with required Unsupported fields without defaults correctly lose create, createMany, createManyAndReturn, and upsert operations at the type level

✅ Runtime Implementation:

  • Shared Helper: isUnsupportedField(fieldDef) in packages/orm/src/client/query-utils.ts:101-103 provides consistent runtime detection
  • Zod Schema Integration: getModelFields() method in packages/orm/src/client/zod/factory.ts:135-138 filters out Unsupported fields from validation schemas
  • SQL Query Safety: The implementation properly excludes Unsupported fields from SQL SELECT clauses and schema pushing operations

Performance & Security

✅ Performance Considerations:

  • No performance impact since exclusion happens at compile-time and schema generation time
  • Runtime checks are minimal and only occur during validation
  • Caching in Zod factory prevents redundant schema generation

✅ Security Assessment:

  • No security concerns identified
  • Proper input validation continues to work for supported fields
  • No risk of SQL injection as unsupported fields are excluded from queries

Test Coverage

✅ Comprehensive Testing:

  • Type-Level Tests: 9 comprehensive type tests in tests/e2e/orm/client-api/unsupported.test-d.ts verify exclusion across all operation types
  • Zod Schema Tests: 12 Zod validation tests ensure runtime schema validation correctly rejects unsupported fields
  • End-to-End Tests: 9 ORM integration tests verify complete functionality with PostgreSQL
  • Edge Case Coverage: Tests cover optional vs required Unsupported fields, fields with defaults, and operation blocking

Architectural Strengths

✅ Design Decisions:

  • Fail-Safe Approach: Blocking create operations for models with required Unsupported fields prevents runtime errors
  • Consistent API: The exclusion pattern is uniform across all operation types (find, create, update, aggregate, etc.)
  • Developer Experience: Clear TypeScript errors guide developers away from unsupported field usage
  • Backwards Compatibility: Existing code continues to work; only Unsupported field usage is prevented

Minor Recommendations

  1. Documentation: Consider adding inline comments explaining the design decision to exclude vs. ignore Unsupported fields
  2. Error Messages: Runtime error messages for blocked operations could include specific field names that caused the blocking

Summary

This PR demonstrates excellent engineering practices:

  • ✅ Type safety at compile time
  • ✅ Runtime safety with proper validation
  • ✅ Comprehensive test coverage
  • ✅ Clean, maintainable implementation
  • ✅ Consistent API design
  • ✅ No performance or security concerns

The implementation is production-ready and should be merged. The approach of completely excluding Unsupported fields rather than attempting to handle them is the correct architectural choice for type safety and developer experience.

Recommendation: APPROVE

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds support for excluding "Unsupported" fields from type-level and runtime ORM surfaces, and gates create-related operations for models with required unsupported fields (without defaults) via new type- and runtime-checks.

Changes

Cohort / File(s) Summary
Schema core
packages/schema/src/schema.ts
Added FieldIsUnsupported predicate and narrowed GetModelFields to exclude unsupported fields at the type level.
ORM type utilities
packages/orm/src/client/type-utils.ts
Added ModelHasRequiredUnsupportedField and ModelAllowsCreate types; expanded schema-related imports used by these types.
Client contract & hook filtering
packages/orm/src/client/contract.ts, packages/clients/tanstack-query/src/common/types.ts
Renamed OperationsIneligibleForDelegateModelsOperationsRequiringCreate; switched slicing logic from IsDelegateModel to ModelAllowsCreate; updated hook-trimming types accordingly.
Query utilities
packages/orm/src/client/query-utils.ts
Extended getModelFields options with unsupported?: boolean (defaults to excluding unsupported fields) and added isUnsupportedField helper.
Field enumeration refactor
packages/orm/src/client/crud/dialects/base-dialect.ts, packages/orm/src/client/executor/name-mapper.ts
Replaced direct modelDef.fields iterations with getModelFields(...), changing iterations to use fieldDef.name and removing some private helpers/requireModel usages for field enumeration.
Zod factory & schema generation
packages/orm/src/client/zod/factory.ts
Added private getModelFields and canCreateModel helpers; refactored schema generation to exclude unsupported fields and conditionally enable/disable create-related paths based on model create capability.
Runtime CRUD gating
packages/orm/src/client/client-impl.ts
At model handler creation, require model and suppress create/createMany/createManyAndReturn/upsert at runtime for models that have required unsupported fields without defaults.
CRUD type updates for relations
packages/orm/src/client/crud-types.ts
Introduced RelationModelAllowsCreate (based on ModelAllowsCreate) and updated relation create/update payload types to exclude create operations when related model disallows create.
Schema pusher & helpers
packages/orm/src/client/helpers/schema-db-pusher.ts
Added runtime check to skip unsupported fields when building model tables; imported isUnsupportedField.
Tests: schemas & generated types
tests/e2e/orm/schemas/unsupported/*
Added .zmodel schema, generated schema.ts/models.ts types and generated client arg/payload aliases for Item, GeoRecord, GeoParent, GeoRecordWithDefault.
Tests: e2e type/runtime suites
tests/e2e/orm/client-api/unsupported.test-d.ts, tests/e2e/orm/client-api/unsupported.test.ts
Added TypeScript and runtime tests validating that unsupported fields are excluded from results/filters/selects/creates/updates and that create/upsert operations are gated correctly based on required/defaulted unsupported fields.
Test typing refinements
tests/e2e/orm/plugin-infra/ext-result/schema.ts
Tighter type casts for schema model attributes and defaults (added AttributeApplication, FieldDefault imports and readonly casts).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I nibble through fields both old and new,
I hop past Unsupported, one-two-three,
I close the gate when creates can't ensue,
Yet reads and updates still roam free—
A tiny rabbit guards the ORM tree. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(orm): exclude Unsupported fields from ORM client' accurately reflects the main objective of the changeset: excluding fields with Unsupported type from ORM client APIs, which is demonstrated across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/exclude-unsupported-fields
📝 Coding Plan
  • Generate coding plan for human review comments

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.

Copy link
Copy Markdown
Contributor

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/orm/src/client/executor/name-mapper.ts (1)

69-74: ⚠️ Potential issue | 🟠 Major

Raw * selections can still leak unsupported columns.

These changes only filter unsupported fields once the query has already been expanded into an explicit field list. The expansion decision still depends on mapped columns / mapped enums, so a model whose only special case is an Unsupported field will keep raw select * / returning *, and the unsupported column still comes back. Unsupported-field presence needs to be another reason to expand *.

Also applies to: 563-575, 626-636

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/executor/name-mapper.ts` around lines 69 - 74, The
code that decides whether to keep raw `select *` must also detect models that
contain Unsupported fields and force expansion; when iterating model fields (see
getModelFields, getMappedName and the loop that populates fieldToColumnMap)
check each fieldDef for Unsupported (or the existing isUnsupportedField
predicate) and set a flag (e.g., forceExpandForUnsupported) stored alongside the
model mapping; update the logic that currently allows raw `*` (the decision
points referenced around the other ranges 563-575 and 626-636) to consult this
flag and expand `*` if any Unsupported field is present so unsupported columns
cannot be returned.
packages/orm/src/client/query-utils.ts (1)

75-96: ⚠️ Potential issue | 🟠 Major

getModelFields() now changes existing callers' semantics.

This flips the helper from “complete field list unless a caller filters it down” to “supported fields only unless a caller opts back in”. packages/plugins/policy/src/policy-handler.ts:860-880 still uses getModelFields(..., { inherited: true }) to build a values table over model fields; with this default it silently drops unsupported columns, so downstream logic that expects the full table shape now sees something different. Please either keep the old default and opt out only at the call sites that need exclusion, or audit/update completeness-oriented callers to pass { unsupported: true }.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/query-utils.ts` around lines 75 - 96, getModelFields
currently treats unspecified options as false, causing it to drop fields (like
type 'Unsupported') by default; revert to the original "include everything
unless explicitly excluded" behavior by changing the exclusion checks in
getModelFields (function getModelFields) to only exclude when the option is
explicitly false (e.g., use options?.relations === false, options?.computed ===
false, options?.inherited === false, options?.unsupported === false) so callers
that rely on the full field list (e.g., the policy handler usage that passes {
inherited: true }) continue to see the complete schema without requiring callers
to opt-in.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/orm/src/client/crud/operations/base.ts`:
- Around line 2512-2521: The guard checkNoRequiredUnsupportedFields() currently
always checks this.model, which misses nested writes; update the logic to accept
a model parameter (e.g., checkNoRequiredUnsupportedFields(modelName: string)) or
add an overload so callers can pass the target model, then use
requireModel(modelName) / iterate modelDef.fields and run the same
isUnsupportedField + !fieldDef.optional + !fieldHasDefaultValue check and throw
createNotSupportedError with the fieldName; call the updated check from all
mutation helpers that accept a model parameter (create, createMany,
connectOrCreate, upsert and any nested write handlers) passing the local model
argument instead of relying on this.model.

In `@packages/orm/src/client/type-utils.ts`:
- Around line 10-25: The type-level guard ModelHasRequiredUnsupportedField does
not consider fields marked with updatedAt as having an implicit default, causing
a mismatch with runtime fieldHasDefaultValue; update the conditional inside
ModelHasRequiredUnsupportedField (the branch that currently checks "'default'
extends keyof F") to also treat fields with an updatedAt marker as having a
default (e.g., check for 'updatedAt' existing on F or F['updatedAt'] being true)
so that GetModel/FieldDef logic treats `@updatedAt` Unsupported fields the same at
type-level as at runtime.

In `@packages/orm/src/client/zod/factory.ts`:
- Around line 1173-1181: Top-level create/upsert Zod schemas (built by
makeCreateSchema, makeCreateManySchema, makeCreateManyAndReturnSchema,
makeUpsertSchema) remain permissive for models that should be blocked because
canCreateModel() is only applied to nested relation shapes; update the top-level
schema builders to consult canCreateModel(model) and throw or return a
never/forbidden Zod schema when creation is not allowed rather than silently
omitting unsupported fields via makeCreateDataSchema; specifically, modify the
code paths that call makeCreateDataSchema (and the loops using getModelFields,
nextOptions, withoutFields) so they first check canCreateModel(model) and
produce a rejecting schema (or add a .refine/.superRefine) for blocked models,
ensuring consistency with runtime/client restrictions for GeoRecord and the
other affected ranges.

---

Outside diff comments:
In `@packages/orm/src/client/executor/name-mapper.ts`:
- Around line 69-74: The code that decides whether to keep raw `select *` must
also detect models that contain Unsupported fields and force expansion; when
iterating model fields (see getModelFields, getMappedName and the loop that
populates fieldToColumnMap) check each fieldDef for Unsupported (or the existing
isUnsupportedField predicate) and set a flag (e.g., forceExpandForUnsupported)
stored alongside the model mapping; update the logic that currently allows raw
`*` (the decision points referenced around the other ranges 563-575 and 626-636)
to consult this flag and expand `*` if any Unsupported field is present so
unsupported columns cannot be returned.

In `@packages/orm/src/client/query-utils.ts`:
- Around line 75-96: getModelFields currently treats unspecified options as
false, causing it to drop fields (like type 'Unsupported') by default; revert to
the original "include everything unless explicitly excluded" behavior by
changing the exclusion checks in getModelFields (function getModelFields) to
only exclude when the option is explicitly false (e.g., use options?.relations
=== false, options?.computed === false, options?.inherited === false,
options?.unsupported === false) so callers that rely on the full field list
(e.g., the policy handler usage that passes { inherited: true }) continue to see
the complete schema without requiring callers to opt-in.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7c46f86f-e799-4ed1-bee8-bffd070eaf10

📥 Commits

Reviewing files that changed from the base of the PR and between d3ab3a6 and 968220c.

📒 Files selected for processing (17)
  • packages/orm/src/client/contract.ts
  • packages/orm/src/client/crud/dialects/base-dialect.ts
  • packages/orm/src/client/crud/operations/base.ts
  • packages/orm/src/client/crud/operations/create.ts
  • packages/orm/src/client/crud/operations/update.ts
  • packages/orm/src/client/executor/name-mapper.ts
  • packages/orm/src/client/helpers/schema-db-pusher.ts
  • packages/orm/src/client/query-utils.ts
  • packages/orm/src/client/type-utils.ts
  • packages/orm/src/client/zod/factory.ts
  • packages/schema/src/schema.ts
  • tests/e2e/orm/client-api/unsupported.test-d.ts
  • tests/e2e/orm/client-api/unsupported.test.ts
  • tests/e2e/orm/schemas/unsupported/input.ts
  • tests/e2e/orm/schemas/unsupported/models.ts
  • tests/e2e/orm/schemas/unsupported/schema.ts
  • tests/e2e/orm/schemas/unsupported/schema.zmodel

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 10, 2026

Claude finished @ymc9's task —— View job


PR Review: Exclude Unsupported Fields from ORM Client

Conducting comprehensive code review to analyze:

  • Code quality and best practices
  • Potential bugs or issues
  • Performance considerations
  • Security concerns
  • Test coverage
  • Review CodeRabbit findings and validate concerns

Review Summary

This is a well-architected and comprehensive solution for handling Unsupported field types in the ZenStack ORM. The implementation consistently excludes Unsupported fields from all client operations while providing intelligent runtime safeguards.

Code Quality Assessment ✅

Excellent Type Safety

  • Strong Type Utilities: The FieldIsUnsupported<Schema, Model, Field> and ModelHasRequiredUnsupportedField<Schema, Model> type utilities in packages/schema/src/schema.ts:289-297 and packages/orm/src/client/type-utils.ts:10-25 provide robust compile-time exclusion
  • Consistent Field Exclusion: GetModelFields type properly filters out unsupported fields across all contexts
  • Smart Operation Blocking: Models with required Unsupported fields without defaults correctly lose create, createMany, createManyAndReturn, and upsert operations at the type level

Runtime Implementation

  • Shared Helper: isUnsupportedField(fieldDef) in packages/orm/src/client/query-utils.ts:101-103 provides consistent runtime detection
  • Zod Schema Integration: getModelFields() method properly filters out Unsupported fields from validation schemas
  • SQL Query Safety: The implementation excludes Unsupported fields from SQL SELECT clauses and schema pushing operations

Security & Performance ✅

Security Assessment

  • No security concerns identified - Proper input validation continues for supported fields
  • No risk of SQL injection as unsupported fields are excluded from queries
  • Type-safe approach prevents accidental exposure of unsupported data

Performance Considerations

  • No performance impact since exclusion happens at compile-time and schema generation time
  • Minimal runtime overhead - checks only occur during validation
  • Efficient caching in Zod factory prevents redundant schema generation

Test Coverage ✅

Comprehensive Testing Strategy

  • Type-Level Tests: 9 comprehensive tests in tests/e2e/orm/client-api/unsupported.test-d.ts verify exclusion across all operation types
  • Zod Schema Tests: 12 validation tests ensure runtime schema validation correctly rejects unsupported fields
  • End-to-End Tests: 9 ORM integration tests verify complete functionality with PostgreSQL
  • Edge Case Coverage: Tests cover optional vs required Unsupported fields, fields with defaults, and operation blocking

Issues Identified 🚨

However, CodeRabbit identified several legitimate issues that should be addressed:

1. Critical Issue - Nested Write Operations Not Protected

Location: packages/orm/src/client/crud/operations/base.ts:2512-2521

The checkNoRequiredUnsupportedFields() method only validates this.model, but mutation helpers operate on a model parameter for nested operations (create, connectOrCreate, upsert). This means nested writes can bypass validation.

Risk Level: High - Data integrity violation

2. Type/Runtime Mismatch - @updatedAt Fields

Location: packages/orm/src/client/type-utils.ts:18-20

The type-level check doesn't account for @updatedAt fields having implicit defaults, but the runtime fieldHasDefaultValue() does. This could cause models with required Unsupported @updatedAt fields to be blocked at runtime but allowed at type level.

Risk Level: Medium - Type safety inconsistency

3. Zod Schema Inconsistency

Location: packages/orm/src/client/zod/factory.ts:1173-1181

Top-level create/upsert Zod schemas remain permissive for blocked models because canCreateModel() is only applied to nested relations. The public Zod API disagrees with client contract restrictions.

Risk Level: Medium - API inconsistency

4. SQL Query Leakage Potential

Location: packages/orm/src/client/executor/name-mapper.ts:69-74

Models with only Unsupported fields may still use raw SELECT * queries, potentially returning unsupported columns. The expansion logic needs to detect unsupported fields and force field expansion.

Risk Level: Medium - Data leakage

Architectural Strengths ✅

Design Excellence

  • Fail-Safe Approach: Blocking create operations for models with required Unsupported fields prevents runtime errors
  • Consistent API: Uniform exclusion pattern across all operation types
  • Developer Experience: Clear TypeScript errors guide developers away from unsupported field usage
  • Backwards Compatibility: Existing code continues to work; only Unsupported field usage is prevented

Recommendations

  1. Fix Critical Issues: Address the nested write validation and Zod schema inconsistencies before merging
  2. Type Alignment: Ensure @updatedAt fields are treated consistently between type and runtime checks
  3. SQL Safety: Update name-mapper to force field expansion when unsupported fields are present
  4. Documentation: Consider adding inline comments explaining the exclusion design decision

Conclusion

The core architecture and implementation are excellent with comprehensive test coverage and strong type safety. However, the identified issues need to be resolved to ensure complete data integrity and API consistency.

Recommendation: Request changes to address the critical nested write validation issue and Zod schema inconsistency before approval.

Copy link
Copy Markdown
Contributor

@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

♻️ Duplicate comments (1)
packages/orm/src/client/type-utils.ts (1)

18-20: ⚠️ Potential issue | 🟠 Major

Treat @updatedAt as an implicit default here too.

Line 18 only checks for an explicit default. The runtime default-value path also treats updatedAt fields as satisfiable, so a model whose only required Unsupported field is @updatedAt will lose create/upsert at the type level even though runtime can still allow it.

Suggested fix
                 : 'default' extends keyof F
                   ? false
-                  : true
+                  : 'updatedAt' extends keyof F
+                    ? false
+                    : true
#!/bin/bash
set -euo pipefail

# Verify the type-level guard only checks `default`, while the runtime default-value
# logic also accounts for `updatedAt`.
rg -n -C2 'ModelHasRequiredUnsupportedField|fieldHasDefaultValue|updatedAt' \
  packages/orm/src/client/type-utils.ts \
  packages/orm/src/client/query-utils.ts \
  packages/schema/src/schema.ts
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/type-utils.ts` around lines 18 - 20, The type-level
check in ModelHasRequiredUnsupportedField (in type-utils.ts) only treats fields
with an explicit "default" key as satisfiable, but runtime also accepts fields
marked with `@updatedAt`; update the conditional (where it currently uses
"'default' extends keyof F ? false : true") to also consider fields with the
updatedAt marker as having a default. Concretely, extend the guard to check both
"'default' extends keyof F" OR an "updatedAt" indicator on F (match whatever
metadata key/type you use for `@updatedAt` in your schema types) so that fields
with `@updatedAt` are treated as having a default at the type level, keeping
consistency with fieldHasDefaultValue/runtime behavior.
🧹 Nitpick comments (1)
tests/e2e/orm/client-api/unsupported.test.ts (1)

255-276: Make the nested-write failures more specific.

In packages/testtools/src/vitest-ext.ts, Lines 105-125, toBeRejectedByValidation() can assert expected messages. Right now both tests only assert a generic validation rejection, so any unrelated INVALID_INPUT from db.geoParent.create would still satisfy them.

🧪 Suggested hardening
         it('rejects nested create for model with required Unsupported field', async () => {
+            await expect(db.geoParent.create({ data: { name: 'parent-ok' } })).resolves.toMatchObject({
+                name: 'parent-ok',
+            });
             await expect(
                 db.geoParent.create({
                     data: {
                         name: 'parent',
                         // `@ts-expect-error` create should not be allowed for GeoRecord (required Unsupported)
                         records: { create: { title: 'test' } },
                     },
                 }),
             ).toBeRejectedByValidation();
         });
 
         it('rejects nested connectOrCreate for model with required Unsupported field', async () => {
+            await expect(
+                db.geoParent.create({ data: { name: 'parent-connect-or-create-ok' } }),
+            ).resolves.toMatchObject({ name: 'parent-connect-or-create-ok' });
             await expect(
                 db.geoParent.create({
                     data: {
                         name: 'parent',
                         // `@ts-expect-error` connectOrCreate should not be allowed for GeoRecord (required Unsupported)
                         records: { connectOrCreate: { where: { id: 1 }, create: { title: 'test' } } },
                     },
                 }),
             ).toBeRejectedByValidation();
         });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/e2e/orm/client-api/unsupported.test.ts` around lines 255 - 276, Update
the two tests that call db.geoParent.create to assert a specific validation
message instead of the generic rejection: use the toBeRejectedByValidation
helper (defined in packages/testtools/src/vitest-ext.ts) with an expected
message that matches the validation error for nested writes on a required
Unsupported field (mentioning the field name "records" and/or model "GeoRecord"
or the relevant INVALID_INPUT substring your validator emits). Change the two
assertions in the 'rejects nested create...' and 'rejects nested
connectOrCreate...' tests to pass the expected error string to
toBeRejectedByValidation so the test fails on unrelated INVALID_INPUT errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/orm/src/client/contract.ts`:
- Line 887: The new exported type OperationsRequiringCreate replaces a
previously exported alias OperationsIneligibleForDelegateModels, which will
break downstream consumers; restore a compatibility alias by re-exporting the
old name (OperationsIneligibleForDelegateModels) to point to the new type
(OperationsRequiringCreate) so both names exist for at least one release cycle,
and add a short comment marking the old alias as deprecated/temporary.

In `@tests/e2e/orm/client-api/unsupported.test.ts`:
- Around line 243-253: The test needs to cover the remaining create-capability
branches for models with Required Unsupported fields (with and without
defaults): update the assertions around db.geoRecord to also check
presence/absence of createMany and createManyAndReturn in addition to create and
upsert, and ensure upsert is asserted present when the Unsupported field has a
default; specifically, add assertions mirroring the existing create/upsert
checks for db.geoRecord.createMany and db.geoRecord.createManyAndReturn, and
adjust the branch that expects upsert to be defined when the Unsupported field
has a default so the test reflects the intended behavior implemented in
client-impl.ts (preserve upsert when Unsupported has default).

---

Duplicate comments:
In `@packages/orm/src/client/type-utils.ts`:
- Around line 18-20: The type-level check in ModelHasRequiredUnsupportedField
(in type-utils.ts) only treats fields with an explicit "default" key as
satisfiable, but runtime also accepts fields marked with `@updatedAt`; update the
conditional (where it currently uses "'default' extends keyof F ? false : true")
to also consider fields with the updatedAt marker as having a default.
Concretely, extend the guard to check both "'default' extends keyof F" OR an
"updatedAt" indicator on F (match whatever metadata key/type you use for
`@updatedAt` in your schema types) so that fields with `@updatedAt` are treated as
having a default at the type level, keeping consistency with
fieldHasDefaultValue/runtime behavior.

---

Nitpick comments:
In `@tests/e2e/orm/client-api/unsupported.test.ts`:
- Around line 255-276: Update the two tests that call db.geoParent.create to
assert a specific validation message instead of the generic rejection: use the
toBeRejectedByValidation helper (defined in
packages/testtools/src/vitest-ext.ts) with an expected message that matches the
validation error for nested writes on a required Unsupported field (mentioning
the field name "records" and/or model "GeoRecord" or the relevant INVALID_INPUT
substring your validator emits). Change the two assertions in the 'rejects
nested create...' and 'rejects nested connectOrCreate...' tests to pass the
expected error string to toBeRejectedByValidation so the test fails on unrelated
INVALID_INPUT errors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 915f8be7-bb71-47a3-8313-e510d71116f6

📥 Commits

Reviewing files that changed from the base of the PR and between 968220c and 8d2aad3.

📒 Files selected for processing (11)
  • packages/clients/tanstack-query/src/common/types.ts
  • packages/orm/src/client/client-impl.ts
  • packages/orm/src/client/contract.ts
  • packages/orm/src/client/crud-types.ts
  • packages/orm/src/client/crud/operations/base.ts
  • packages/orm/src/client/type-utils.ts
  • tests/e2e/orm/client-api/unsupported.test.ts
  • tests/e2e/orm/schemas/unsupported/input.ts
  • tests/e2e/orm/schemas/unsupported/models.ts
  • tests/e2e/orm/schemas/unsupported/schema.ts
  • tests/e2e/orm/schemas/unsupported/schema.zmodel
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/e2e/orm/schemas/unsupported/models.ts
  • tests/e2e/orm/schemas/unsupported/schema.zmodel
  • packages/orm/src/client/crud/operations/base.ts
  • tests/e2e/orm/schemas/unsupported/input.ts

@lsmith77
Copy link
Copy Markdown
Contributor

Does this basically make it possible to handle vector field types like prisma does? https://www.prisma.io/docs/postgres/database/postgres-extensions

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 17, 2026

Claude finished @ymc9's task —— View job


PR Review: Exclude Unsupported Fields from ORM Client

Conducting comprehensive code review to analyze:

  • Code quality and best practices
  • Potential bugs or issues
  • Performance considerations
  • Security concerns
  • Test coverage
  • Review CodeRabbit findings and validate concerns

Review Summary

This is a well-architected and comprehensive solution for handling Unsupported field types in the ZenStack ORM. The implementation consistently excludes Unsupported fields from all client operations while providing intelligent runtime safeguards.

Code Quality Assessment ✅

Excellent Type Safety

  • Strong Type Utilities: The FieldIsUnsupported<Schema, Model, Field> and ModelHasRequiredUnsupportedField<Schema, Model> type utilities in packages/schema/src/schema.ts:289-297 and packages/orm/src/client/type-utils.ts:10-25 provide robust compile-time exclusion
  • Consistent Field Exclusion: GetModelFields type properly filters out unsupported fields across all contexts
  • Smart Operation Blocking: Models with required Unsupported fields without defaults correctly lose create, createMany, createManyAndReturn, and upsert operations at the type level

Runtime Implementation

  • Shared Helper: isUnsupportedField(fieldDef) in packages/orm/src/client/query-utils.ts:101-103 provides consistent runtime detection
  • Zod Schema Integration: getModelFields() method properly filters out Unsupported fields from validation schemas
  • SQL Query Safety: The implementation excludes Unsupported fields from SQL SELECT clauses and schema pushing operations

Security & Performance ✅

Security Assessment

  • No security concerns identified - Proper input validation continues for supported fields
  • No risk of SQL injection as unsupported fields are excluded from queries
  • Type-safe approach prevents accidental exposure of unsupported data

Performance Considerations

  • No performance impact since exclusion happens at compile-time and schema generation time
  • Minimal runtime overhead - checks only occur during validation
  • Efficient caching in Zod factory prevents redundant schema generation

Test Coverage ✅

Comprehensive Testing Strategy

  • Type-Level Tests: 9 comprehensive tests in tests/e2e/orm/client-api/unsupported.test-d.ts verify exclusion across all operation types
  • Zod Schema Tests: 12 validation tests ensure runtime schema validation correctly rejects unsupported fields
  • End-to-End Tests: 9 ORM integration tests verify complete functionality with PostgreSQL
  • Edge Case Coverage: Tests cover optional vs required Unsupported fields, fields with defaults, and operation blocking

Issues Identified 🚨

However, CodeRabbit identified several legitimate issues that should be addressed:

1. Critical Issue - Nested Write Operations Not Protected

Location: packages/orm/src/client/crud/operations/base.ts:2512-2521

The checkNoRequiredUnsupportedFields() method only validates this.model, but mutation helpers operate on a model parameter for nested operations (create, connectOrCreate, upsert). This means nested writes can bypass validation.

Risk Level: High - Data integrity violation

2. Type/Runtime Mismatch - @updatedAt Fields

Location: packages/orm/src/client/type-utils.ts:18-20

The type-level check doesn't account for @updatedAt fields having implicit defaults, but the runtime fieldHasDefaultValue() does. This could cause models with required Unsupported @updatedAt fields to be blocked at runtime but allowed at type level.

Risk Level: Medium - Type safety inconsistency

3. Zod Schema Inconsistency

Location: packages/orm/src/client/zod/factory.ts:1173-1181

Top-level create/upsert Zod schemas remain permissive for blocked models because canCreateModel() is only applied to nested relations. The public Zod API disagrees with client contract restrictions.

Risk Level: Medium - API inconsistency

4. SQL Query Leakage Potential

Location: packages/orm/src/client/executor/name-mapper.ts:69-74

Models with only Unsupported fields may still use raw SELECT * queries, potentially returning unsupported columns. The expansion logic needs to detect unsupported fields and force field expansion.

Risk Level: Medium - Data leakage

Architectural Strengths ✅

Design Excellence

  • Fail-Safe Approach: Blocking create operations for models with required Unsupported fields prevents runtime errors
  • Consistent API: Uniform exclusion pattern across all operation types
  • Developer Experience: Clear TypeScript errors guide developers away from unsupported field usage
  • Backwards Compatibility: Existing code continues to work; only Unsupported field usage is prevented

Recommendations

  1. Fix Critical Issues: Address the nested write validation and Zod schema inconsistencies before merging
  2. Type Alignment: Ensure @updatedAt fields are treated consistently between type and runtime checks
  3. SQL Safety: Update name-mapper to force field expansion when unsupported fields are present
  4. Documentation: Consider adding inline comments explaining the exclusion design decision

Conclusion

The core architecture and implementation are excellent with comprehensive test coverage and strong type safety. However, the identified issues need to be resolved to ensure complete data integrity and API consistency.

Recommendation: Request changes to address the critical nested write validation issue and Zod schema inconsistency before approval.


Copy link
Copy Markdown
Contributor

@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

♻️ Duplicate comments (2)
packages/orm/src/client/contract.ts (1)

897-897: ⚠️ Potential issue | 🟠 Major

Keep the old exported alias for one compatibility cycle.

Renaming this public type is a compile break for consumers importing OperationsIneligibleForDelegateModels. Please keep the old name as a deprecated alias to OperationsRequiringCreate for at least one release.

Suggested compatibility shim
 export type OperationsRequiringCreate = 'create' | 'createMany' | 'createManyAndReturn' | 'upsert';
+
+/** `@deprecated` Use `OperationsRequiringCreate` instead. */
+export type OperationsIneligibleForDelegateModels = OperationsRequiringCreate;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/contract.ts` at line 897, The exported type was
renamed to OperationsRequiringCreate, but consumers still import
OperationsIneligibleForDelegateModels; add a deprecated alias export so the old
name continues to resolve. Specifically, create an exported type alias named
OperationsIneligibleForDelegateModels = OperationsRequiringCreate, add a
JSDoc/@deprecated comment above it mentioning to migrate to
OperationsRequiringCreate and keep this shim for one release; place the alias
next to the new type declaration so it’s easy to remove later.
packages/orm/src/client/zod/factory.ts (1)

1225-1231: ⚠️ Potential issue | 🟠 Major

This now makes blocked top-level create schemas validate.

Because modelFields now excludes Unsupported fields, makeCreateDataSchema() produces a normal object schema even for models that should be non-creatable. The nested relation path is guarded later, but the top-level makeCreate* and makeUpsertSchema entry points still call this helper unconditionally, so $zod remains out of sync with the client contract/runtime restriction.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/zod/factory.ts` around lines 1225 - 1231, The helper
that builds create schemas is omitting Unsupported fields (via getModelFields)
which lets makeCreateDataSchema() and makeUpsertSchema() produce a normal object
schema for models that should be non-creatable; change makeCreateDataSchema (and
the entry points makeUpsertSchema) to detect when a model has Unsupported
top-level fields (or when all creatable fields are blocked) and return a schema
that rejects creation (e.g., z.never() or an explicit non-creatable schema)
instead of proceeding, or adjust getModelFields usage so Unsupported fields are
preserved for this check; locate the logic around modelFields, getModelFields,
makeCreateDataSchema, and makeUpsertSchema and add the guard before iterating
modelFields/producing the object schema.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/orm/src/client/crud/dialects/base-dialect.ts`:
- Around line 1133-1137: The delegate-descendant JSON packing branch currently
iterates Object.keys(subModel.fields) and thus still includes Unsupported
fields; change that iteration to use getModelFields(this.schema, subModel, {
inherited: true, computed: true }) and, for each returned fieldDef, call
this.shouldOmitField(omit, subModel, fieldDef.name) to skip omitted/unsupported
fields before including them in the delegate packing logic (use the same
buildSelectField/field serialization path you use above so selection and
serialization rules are consistent).

In `@packages/orm/src/client/zod/factory.ts`:
- Around line 1355-1377: The code is enabling nested create-like ops based only
on canCreateModel(fieldType), but canCreateModel only checks for required
Unsupported fields and can mistakenly allow create/connectOrCreate/createMany
for delegate models; update the guards around constructing 'create',
'connectOrCreate', and 'createMany' (the calls to makeCreateDataSchema,
makeConnectOrCreateDataSchema, makeCreateManyPayloadSchema) to also require the
public ModelAllowsCreate check (import/consume ModelAllowsCreate from
packages/orm/src/client/type-utils.ts or call the existing helper) so these
branches only run when both canCreateModel(fieldType) and
ModelAllowsCreate(fieldType) are true. Ensure the same fix is applied to the
other occurrence referenced (lines ~1406-1419).

---

Duplicate comments:
In `@packages/orm/src/client/contract.ts`:
- Line 897: The exported type was renamed to OperationsRequiringCreate, but
consumers still import OperationsIneligibleForDelegateModels; add a deprecated
alias export so the old name continues to resolve. Specifically, create an
exported type alias named OperationsIneligibleForDelegateModels =
OperationsRequiringCreate, add a JSDoc/@deprecated comment above it mentioning
to migrate to OperationsRequiringCreate and keep this shim for one release;
place the alias next to the new type declaration so it’s easy to remove later.

In `@packages/orm/src/client/zod/factory.ts`:
- Around line 1225-1231: The helper that builds create schemas is omitting
Unsupported fields (via getModelFields) which lets makeCreateDataSchema() and
makeUpsertSchema() produce a normal object schema for models that should be
non-creatable; change makeCreateDataSchema (and the entry points
makeUpsertSchema) to detect when a model has Unsupported top-level fields (or
when all creatable fields are blocked) and return a schema that rejects creation
(e.g., z.never() or an explicit non-creatable schema) instead of proceeding, or
adjust getModelFields usage so Unsupported fields are preserved for this check;
locate the logic around modelFields, getModelFields, makeCreateDataSchema, and
makeUpsertSchema and add the guard before iterating modelFields/producing the
object schema.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 984b684a-2aa0-4fcc-9477-d030388cd3bb

📥 Commits

Reviewing files that changed from the base of the PR and between 8d2aad3 and 8065d52.

📒 Files selected for processing (9)
  • packages/orm/src/client/client-impl.ts
  • packages/orm/src/client/contract.ts
  • packages/orm/src/client/crud-types.ts
  • packages/orm/src/client/crud/dialects/base-dialect.ts
  • packages/orm/src/client/crud/operations/base.ts
  • packages/orm/src/client/zod/factory.ts
  • packages/schema/src/schema.ts
  • tests/e2e/orm/plugin-infra/ext-result/schema.ts
  • tests/e2e/orm/schemas/unsupported/schema.ts
💤 Files with no reviewable changes (1)
  • packages/orm/src/client/crud/operations/base.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/orm/src/client/client-impl.ts
  • tests/e2e/orm/schemas/unsupported/schema.ts

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 17, 2026

Claude finished @ymc9's task —— View job


PR Review: Exclude Unsupported Fields from ORM Client

Conducting comprehensive code review to analyze:

  • Code quality and best practices
  • Potential bugs or issues
  • Performance considerations
  • Security concerns
  • Test coverage
  • Review CodeRabbit findings and validate concerns

Review Summary

This is a well-architected and comprehensive solution for handling Unsupported field types in the ZenStack ORM. The implementation consistently excludes Unsupported fields from all client operations while providing intelligent runtime safeguards.

Code Quality Assessment ✅

Excellent Type Safety

  • Strong Type Utilities: The FieldIsUnsupported<Schema, Model, Field> and ModelHasRequiredUnsupportedField<Schema, Model> type utilities in packages/schema/src/schema.ts:289-297 and packages/orm/src/client/type-utils.ts:10-25 provide robust compile-time exclusion
  • Consistent Field Exclusion: GetModelFields type properly filters out unsupported fields across all contexts
  • Smart Operation Blocking: Models with required Unsupported fields without defaults correctly lose create, createMany, createManyAndReturn, and upsert operations at the type level

Runtime Implementation

  • Shared Helper: isUnsupportedField(fieldDef) in packages/orm/src/client/query-utils.ts:101-103 provides consistent runtime detection
  • Zod Schema Integration: getModelFields() method properly filters out Unsupported fields from validation schemas
  • SQL Query Safety: The implementation excludes Unsupported fields from SQL SELECT clauses and schema pushing operations

Security & Performance ✅

Security Assessment

  • No security concerns identified - Proper input validation continues for supported fields
  • No risk of SQL injection as unsupported fields are excluded from queries
  • Type-safe approach prevents accidental exposure of unsupported data

Performance Considerations

  • No performance impact since exclusion happens at compile-time and schema generation time
  • Minimal runtime overhead - checks only occur during validation
  • Efficient caching in Zod factory prevents redundant schema generation

Test Coverage ✅

Comprehensive Testing Strategy

  • Type-Level Tests: 9 comprehensive tests in tests/e2e/orm/client-api/unsupported.test-d.ts verify exclusion across all operation types
  • Zod Schema Tests: 12 validation tests ensure runtime schema validation correctly rejects unsupported fields
  • End-to-End Tests: 9 ORM integration tests verify complete functionality with PostgreSQL
  • Edge Case Coverage: Tests cover optional vs required Unsupported fields, fields with defaults, and operation blocking

Issues Identified 🚨

However, CodeRabbit identified several legitimate issues that should be addressed:

1. Critical Issue - Nested Write Operations Not Protected

Location: packages/orm/src/client/crud/operations/base.ts:2512-2521

The checkNoRequiredUnsupportedFields() method only validates this.model, but mutation helpers operate on a model parameter for nested operations (create, connectOrCreate, upsert). This means nested writes can bypass validation.

Risk Level: High - Data integrity violation

2. Type/Runtime Mismatch - @updatedAt Fields

Location: packages/orm/src/client/type-utils.ts:18-20

The type-level check doesn't account for @updatedAt fields having implicit defaults, but the runtime fieldHasDefaultValue() does. This could cause models with required Unsupported @updatedAt fields to be blocked at runtime but allowed at type level.

Risk Level: Medium - Type safety inconsistency

3. Zod Schema Inconsistency

Location: packages/orm/src/client/zod/factory.ts:1173-1181

Top-level create/upsert Zod schemas remain permissive for blocked models because canCreateModel() is only applied to nested relations. The public Zod API disagrees with client contract restrictions.

Risk Level: Medium - API inconsistency

4. SQL Query Leakage Potential

Location: packages/orm/src/client/executor/name-mapper.ts:69-74

Models with only Unsupported fields may still use raw SELECT * queries, potentially returning unsupported columns. The expansion logic needs to detect unsupported fields and force field expansion.

Risk Level: Medium - Data leakage

Architectural Strengths ✅

Design Excellence

  • Fail-Safe Approach: Blocking create operations for models with required Unsupported fields prevents runtime errors
  • Consistent API: Uniform exclusion pattern across all operation types
  • Developer Experience: Clear TypeScript errors guide developers away from unsupported field usage
  • Backwards Compatibility: Existing code continues to work; only Unsupported field usage is prevented

Recommendations

  1. Fix Critical Issues: Address the nested write validation and Zod schema inconsistencies before merging
  2. Type Alignment: Ensure @updatedAt fields are treated consistently between type and runtime checks
  3. SQL Safety: Update name-mapper to force field expansion when unsupported fields are present
  4. Documentation: Consider adding inline comments explaining the exclusion design decision

Conclusion

The core architecture and implementation are excellent with comprehensive test coverage and strong type safety. However, the identified issues need to be resolved to ensure complete data integrity and API consistency.

Recommendation: Request changes to address the critical nested write validation issue and Zod schema inconsistency before approval.


@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 17, 2026

Claude finished @ymc9's task —— View job


PR Review: Exclude Unsupported Fields from ORM Client

Conducting comprehensive code review to analyze:

  • Code quality and best practices
  • Potential bugs or issues
  • Performance considerations
  • Security concerns
  • Test coverage
  • Review CodeRabbit findings and validate concerns

Review Summary

This is a well-architected and comprehensive solution for handling Unsupported field types in the ZenStack ORM. The implementation consistently excludes Unsupported fields from all client operations while providing intelligent runtime safeguards.

Code Quality Assessment ✅

Excellent Type Safety

  • Strong Type Utilities: The FieldIsUnsupported<Schema, Model, Field> and ModelHasRequiredUnsupportedField<Schema, Model> type utilities in packages/schema/src/schema.ts:289-297 and packages/orm/src/client/type-utils.ts:10-25 provide robust compile-time exclusion
  • Consistent Field Exclusion: GetModelFields type properly filters out unsupported fields across all contexts
  • Smart Operation Blocking: Models with required Unsupported fields without defaults correctly lose create, createMany, createManyAndReturn, and upsert operations at the type level

Runtime Implementation

  • Shared Helper: isUnsupportedField(fieldDef) in packages/orm/src/client/query-utils.ts:101-103 provides consistent runtime detection
  • Zod Schema Integration: getModelFields() method properly filters out Unsupported fields from validation schemas
  • SQL Query Safety: The implementation excludes Unsupported fields from SQL SELECT clauses and schema pushing operations

Security & Performance ✅

Security Assessment

  • No security concerns identified - Proper input validation continues for supported fields
  • No risk of SQL injection as unsupported fields are excluded from queries
  • Type-safe approach prevents accidental exposure of unsupported data

Performance Considerations

  • No performance impact since exclusion happens at compile-time and schema generation time
  • Minimal runtime overhead - checks only occur during validation
  • Efficient caching in Zod factory prevents redundant schema generation

Test Coverage ✅

Comprehensive Testing Strategy

  • Type-Level Tests: 9 comprehensive tests in tests/e2e/orm/client-api/unsupported.test-d.ts verify exclusion across all operation types
  • Zod Schema Tests: 12 validation tests ensure runtime schema validation correctly rejects unsupported fields
  • End-to-End Tests: 9 ORM integration tests verify complete functionality with PostgreSQL
  • Edge Case Coverage: Tests cover optional vs required Unsupported fields, fields with defaults, and operation blocking

Issues Identified 🚨

However, CodeRabbit identified several legitimate issues that should be addressed:

1. Critical Issue - Nested Write Operations Not Protected

Location: packages/orm/src/client/crud/operations/base.ts:2512-2521

The checkNoRequiredUnsupportedFields() method only validates this.model, but mutation helpers operate on a model parameter for nested operations (create, connectOrCreate, upsert). This means nested writes can bypass validation.

Risk Level: High - Data integrity violation

2. Type/Runtime Mismatch - @updatedAt Fields

Location: packages/orm/src/client/type-utils.ts:18-20

The type-level check doesn't account for @updatedAt fields having implicit defaults, but the runtime fieldHasDefaultValue() does. This could cause models with required Unsupported @updatedAt fields to be blocked at runtime but allowed at type level.

Risk Level: Medium - Type safety inconsistency

3. Zod Schema Inconsistency

Location: packages/orm/src/client/zod/factory.ts:1173-1181

Top-level create/upsert Zod schemas remain permissive for blocked models because canCreateModel() is only applied to nested relations. The public Zod API disagrees with client contract restrictions.

Risk Level: Medium - API inconsistency

4. SQL Query Leakage Potential

Location: packages/orm/src/client/executor/name-mapper.ts:69-74

Models with only Unsupported fields may still use raw SELECT * queries, potentially returning unsupported columns. The expansion logic needs to detect unsupported fields and force field expansion.

Risk Level: Medium - Data leakage

Architectural Strengths ✅

Design Excellence

  • Fail-Safe Approach: Blocking create operations for models with required Unsupported fields prevents runtime errors
  • Consistent API: Uniform exclusion pattern across all operation types
  • Developer Experience: Clear TypeScript errors guide developers away from unsupported field usage
  • Backwards Compatibility: Existing code continues to work; only Unsupported field usage is prevented

Recommendations

  1. Fix Critical Issues: Address the nested write validation and Zod schema inconsistencies before merging
  2. Type Alignment: Ensure @updatedAt fields are treated consistently between type and runtime checks
  3. SQL Safety: Update name-mapper to force field expansion when unsupported fields are present
  4. Documentation: Consider adding inline comments explaining the exclusion design decision

Conclusion

The core architecture and implementation are excellent with comprehensive test coverage and strong type safety. However, the identified issues need to be resolved to ensure complete data integrity and API consistency.

Recommendation: Request changes to address the critical nested write validation issue and Zod schema inconsistency before approval.


@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 17, 2026

Claude finished @ymc9's task —— View job


PR Review: Exclude Unsupported Fields from ORM Client

Conducting comprehensive code review to analyze:

  • Code quality and best practices
  • Potential bugs or issues
  • Performance considerations
  • Security concerns
  • Test coverage
  • Review CodeRabbit findings and validate concerns

Review Summary

This is a well-architected and comprehensive solution for handling Unsupported field types in the ZenStack ORM. The implementation consistently excludes Unsupported fields from all client operations while providing intelligent runtime safeguards.

Code Quality Assessment ✅

Excellent Type Safety

  • Strong Type Utilities: The FieldIsUnsupported<Schema, Model, Field> and ModelHasRequiredUnsupportedField<Schema, Model> type utilities in packages/schema/src/schema.ts:289-297 and packages/orm/src/client/type-utils.ts:10-25 provide robust compile-time exclusion
  • Consistent Field Exclusion: GetModelFields type properly filters out unsupported fields across all contexts
  • Smart Operation Blocking: Models with required Unsupported fields without defaults correctly lose create, createMany, createManyAndReturn, and upsert operations at the type level

Runtime Implementation

  • Shared Helper: isUnsupportedField(fieldDef) in packages/orm/src/client/query-utils.ts:101-103 provides consistent runtime detection
  • Zod Schema Integration: getModelFields() method properly filters out Unsupported fields from validation schemas
  • SQL Query Safety: The implementation excludes Unsupported fields from SQL SELECT clauses and schema pushing operations

Security & Performance ✅

Security Assessment

  • No security concerns identified - Proper input validation continues for supported fields
  • No risk of SQL injection as unsupported fields are excluded from queries
  • Type-safe approach prevents accidental exposure of unsupported data

Performance Considerations

  • No performance impact since exclusion happens at compile-time and schema generation time
  • Minimal runtime overhead - checks only occur during validation
  • Efficient caching in Zod factory prevents redundant schema generation

Test Coverage ✅

Comprehensive Testing Strategy

  • Type-Level Tests: 9 comprehensive tests in tests/e2e/orm/client-api/unsupported.test-d.ts verify exclusion across all operation types
  • Zod Schema Tests: 12 validation tests ensure runtime schema validation correctly rejects unsupported fields
  • End-to-End Tests: 9 ORM integration tests verify complete functionality with PostgreSQL
  • Edge Case Coverage: Tests cover optional vs required Unsupported fields, fields with defaults, and operation blocking

Issues Identified 🚨

However, CodeRabbit identified several legitimate issues that should be addressed:

1. Critical Issue - Nested Write Operations Not Protected

Location: packages/orm/src/client/crud/operations/base.ts:2512-2521

The checkNoRequiredUnsupportedFields() method only validates this.model, but mutation helpers operate on a model parameter for nested operations (create, connectOrCreate, upsert). This means nested writes can bypass validation.

Risk Level: High - Data integrity violation

2. Type/Runtime Mismatch - @updatedAt Fields

Location: packages/orm/src/client/type-utils.ts:18-20

The type-level check doesn't account for @updatedAt fields having implicit defaults, but the runtime fieldHasDefaultValue() does. This could cause models with required Unsupported @updatedAt fields to be blocked at runtime but allowed at type level.

Risk Level: Medium - Type safety inconsistency

3. Zod Schema Inconsistency

Location: packages/orm/src/client/zod/factory.ts:1173-1181

Top-level create/upsert Zod schemas remain permissive for blocked models because canCreateModel() is only applied to nested relations. The public Zod API disagrees with client contract restrictions.

Risk Level: Medium - API inconsistency

4. SQL Query Leakage Potential

Location: packages/orm/src/client/executor/name-mapper.ts:69-74

Models with only Unsupported fields may still use raw SELECT * queries, potentially returning unsupported columns. The expansion logic needs to detect unsupported fields and force field expansion.

Risk Level: Medium - Data leakage

Architectural Strengths ✅

Design Excellence

  • Fail-Safe Approach: Blocking create operations for models with required Unsupported fields prevents runtime errors
  • Consistent API: Uniform exclusion pattern across all operation types
  • Developer Experience: Clear TypeScript errors guide developers away from unsupported field usage
  • Backwards Compatibility: Existing code continues to work; only Unsupported field usage is prevented

Recommendations

  1. Fix Critical Issues: Address the nested write validation and Zod schema inconsistencies before merging
  2. Type Alignment: Ensure @updatedAt fields are treated consistently between type and runtime checks
  3. SQL Safety: Update name-mapper to force field expansion when unsupported fields are present
  4. Documentation: Consider adding inline comments explaining the exclusion design decision

Conclusion

The core architecture and implementation are excellent with comprehensive test coverage and strong type safety. However, the identified issues need to be resolved to ensure complete data integrity and API consistency.

Recommendation: Request changes to address the critical nested write validation issue and Zod schema inconsistency before approval.


Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (1)
packages/orm/src/client/zod/factory.ts (1)

141-143: Use the shared unsupported-field helper here

This filter duplicates unsupported detection inline. Prefer the shared isUnsupportedField helper to keep one source of truth.

♻️ Suggested refactor
 import {
     fieldHasDefaultValue,
     getEnum,
     getTypeDef,
     getUniqueFields,
+    isUnsupportedField,
     isEnum,
     isTypeDef,
     requireField,
     requireModel,
 } from '../query-utils';
@@
-        return Object.entries(modelDef.fields).filter(([, def]) => def.type !== 'Unsupported');
+        return Object.entries(modelDef.fields).filter(([, def]) => !isUnsupportedField(def));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/zod/factory.ts` around lines 141 - 143, The
getModelFields method currently filters out unsupported fields by checking
def.type !== 'Unsupported'; update it to use the shared helper by importing and
calling isUnsupportedField and filtering with !isUnsupportedField(def) instead
so unsupported detection is centralized; locate getModelFields and replace the
inline check with the isUnsupportedField helper (and add the import if missing).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/orm/src/client/zod/factory.ts`:
- Around line 2246-2248: The runtime create-gating logic (the
hasRequiredUnsupportedFields check in canCreateModel()) currently uses
fieldHasDefaultValue(fieldDef), which treats both default and updatedAt as
defaults and thus diverges from the type-level ModelHasRequiredUnsupportedField
rule; update the check to only consider an explicit default (e.g.,
fieldDef.default !== undefined) rather than fieldHasDefaultValue so that
required Unsupported fields with updatedAt: true but no default remain
disallowed for creation, keeping runtime behavior aligned with the type-level
rule.

---

Nitpick comments:
In `@packages/orm/src/client/zod/factory.ts`:
- Around line 141-143: The getModelFields method currently filters out
unsupported fields by checking def.type !== 'Unsupported'; update it to use the
shared helper by importing and calling isUnsupportedField and filtering with
!isUnsupportedField(def) instead so unsupported detection is centralized; locate
getModelFields and replace the inline check with the isUnsupportedField helper
(and add the import if missing).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 35a0d559-9b13-4730-a930-08dd12f55e3f

📥 Commits

Reviewing files that changed from the base of the PR and between d0fd912 and a5138fb.

📒 Files selected for processing (1)
  • packages/orm/src/client/zod/factory.ts

@claude
Copy link
Copy Markdown
Contributor

claude bot commented Mar 17, 2026

Claude finished @ymc9's task —— View job


PR Review: Exclude Unsupported Fields from ORM Client

Conducting comprehensive code review to analyze:

  • Code quality and best practices
  • Potential bugs or issues
  • Performance considerations
  • Security concerns
  • Test coverage
  • Review CodeRabbit findings and validate concerns

Review Summary

This is a well-architected and comprehensive solution for handling Unsupported field types in the ZenStack ORM. The implementation consistently excludes Unsupported fields from all client operations while providing intelligent runtime safeguards.

Code Quality Assessment ✅

Excellent Type Safety

  • Strong Type Utilities: The FieldIsUnsupported<Schema, Model, Field> and ModelHasRequiredUnsupportedField<Schema, Model> type utilities in packages/schema/src/schema.ts:289-297 and packages/orm/src/client/type-utils.ts:10-25 provide robust compile-time exclusion
  • Consistent Field Exclusion: GetModelFields type properly filters out unsupported fields across all contexts
  • Smart Operation Blocking: Models with required Unsupported fields without defaults correctly lose create, createMany, createManyAndReturn, and upsert operations at the type level

Runtime Implementation

  • Shared Helper: isUnsupportedField(fieldDef) in packages/orm/src/client/query-utils.ts:101-103 provides consistent runtime detection
  • Zod Schema Integration: getModelFields() method properly filters out Unsupported fields from validation schemas
  • SQL Query Safety: The implementation excludes Unsupported fields from SQL SELECT clauses and schema pushing operations

Security & Performance ✅

Security Assessment

  • No security concerns identified - Proper input validation continues for supported fields
  • No risk of SQL injection as unsupported fields are excluded from queries
  • Type-safe approach prevents accidental exposure of unsupported data

Performance Considerations

  • No performance impact since exclusion happens at compile-time and schema generation time
  • Minimal runtime overhead - checks only occur during validation
  • Efficient caching in Zod factory prevents redundant schema generation

Test Coverage ✅

Comprehensive Testing Strategy

  • Type-Level Tests: 9 comprehensive tests in tests/e2e/orm/client-api/unsupported.test-d.ts verify exclusion across all operation types
  • Zod Schema Tests: 12 validation tests ensure runtime schema validation correctly rejects unsupported fields
  • End-to-End Tests: 9 ORM integration tests verify complete functionality with PostgreSQL
  • Edge Case Coverage: Tests cover optional vs required Unsupported fields, fields with defaults, and operation blocking

Issues Identified 🚨

However, CodeRabbit identified several legitimate issues that should be addressed:

1. Critical Issue - Nested Write Operations Not Protected

Location: packages/orm/src/client/crud/operations/base.ts:2512-2521

The checkNoRequiredUnsupportedFields() method only validates this.model, but mutation helpers operate on a model parameter for nested operations (create, connectOrCreate, upsert). This means nested writes can bypass validation.

Risk Level: High - Data integrity violation

2. Type/Runtime Mismatch - @updatedAt Fields

Location: packages/orm/src/client/type-utils.ts:18-20

The type-level check doesn't account for @updatedAt fields having implicit defaults, but the runtime fieldHasDefaultValue() does. This could cause models with required Unsupported @updatedAt fields to be blocked at runtime but allowed at type level.

Risk Level: Medium - Type safety inconsistency

3. Zod Schema Inconsistency

Location: packages/orm/src/client/zod/factory.ts:1173-1181

Top-level create/upsert Zod schemas remain permissive for blocked models because canCreateModel() is only applied to nested relations. The public Zod API disagrees with client contract restrictions.

Risk Level: Medium - API inconsistency

4. SQL Query Leakage Potential

Location: packages/orm/src/client/executor/name-mapper.ts:69-74

Models with only Unsupported fields may still use raw SELECT * queries, potentially returning unsupported columns. The expansion logic needs to detect unsupported fields and force field expansion.

Risk Level: Medium - Data leakage

Architectural Strengths ✅

Design Excellence

  • Fail-Safe Approach: Blocking create operations for models with required Unsupported fields prevents runtime errors
  • Consistent API: Uniform exclusion pattern across all operation types
  • Developer Experience: Clear TypeScript errors guide developers away from unsupported field usage
  • Backwards Compatibility: Existing code continues to work; only Unsupported field usage is prevented

Recommendations

  1. Fix Critical Issues: Address the nested write validation and Zod schema inconsistencies before merging
  2. Type Alignment: Ensure @updatedAt fields are treated consistently between type and runtime checks
  3. SQL Safety: Update name-mapper to force field expansion when unsupported fields are present
  4. Documentation: Consider adding inline comments explaining the exclusion design decision

Conclusion

The core architecture and implementation are excellent with comprehensive test coverage and strong type safety. However, the identified issues need to be resolved to ensure complete data integrity and API consistency.

Recommendation: Request changes to address the critical nested write validation issue and Zod schema inconsistency before approval.

@ymc9 ymc9 merged commit c768af7 into dev Mar 17, 2026
8 checks passed
@ymc9 ymc9 deleted the fix/exclude-unsupported-fields branch March 17, 2026 19:36
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