Skip to content

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

Open
ymc9 wants to merge 2 commits intodevfrom
fix/exclude-unsupported-fields
Open

fix(orm): exclude Unsupported fields from ORM client#2468
ymc9 wants to merge 2 commits intodevfrom
fix/exclude-unsupported-fields

Conversation

@ymc9
Copy link
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

    • Added support for database-unsupported field types in ORM schemas with automatic operation restrictions—models with required unsupported fields cannot be created, while operations like read, update, and delete remain available.
    • Unsupported fields are now automatically excluded from query filters, selections, sortings, and payloads, ensuring type-safe interactions.
    • Runtime validation enforces these constraints, preventing invalid data operations.
  • Tests

    • Added comprehensive test coverage for unsupported field handling across query operations and edge cases.

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 <[email protected]>
@claude
Copy link
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
Contributor

coderabbitai bot commented Mar 9, 2026

📝 Walkthrough

Walkthrough

This pull request introduces support for filtering unsupported fields throughout the ORM. The system now detects models with required unsupported fields lacking defaults and conditionally disables create operations, replacing delegate-model-based filtering with create-ability conditions across type definitions, runtime validation, Zod schema generation, and client APIs.

Changes

Cohort / File(s) Summary
Type System Core
packages/schema/src/schema.ts, packages/orm/src/client/type-utils.ts
Added FieldIsUnsupported and ModelAllowsCreate type predicates. Updated GetModelFields to exclude unsupported fields. Renamed OperationsIneligibleForDelegateModels to OperationsRequiringCreate in contract and updated filtering logic to use ModelAllowsCreate.
CRUD & Contract Types
packages/orm/src/client/contract.ts, packages/orm/src/client/crud-types.ts
Replaced delegate-model checks with ModelAllowsCreate for operation availability. Introduced RelationModelAllowsCreate to gate create operations on relations based on target model create-ability.
Runtime Field Access
packages/orm/src/client/query-utils.ts, packages/orm/src/client/crud/dialects/base-dialect.ts, packages/orm/src/client/executor/name-mapper.ts, packages/orm/src/client/helpers/schema-db-pusher.ts
Added getModelFields() options for unsupported field filtering and new isUnsupportedField() helper. Refactored field iteration across multiple modules to exclude unsupported fields and use centralized field-access utilities.
Zod Schema Generation
packages/orm/src/client/zod/factory.ts
Added private helpers getModelFields() and canCreateModel() to detect model create-ability. Refactored schema generation paths to conditionally exclude create/upsert/connectOrCreate operations for models with required unsupported fields.
Base Operations
packages/orm/src/client/crud/operations/base.ts
Narrowed type of combinedWhere and added doNormalizeArgs() helper for update flow normalization.
Client Implementation
packages/orm/src/client/client-impl.ts
Added runtime filtering to suppress create operations for models with required unsupported fields without defaults after slicing-based filtering.
TanStack Query Integration
packages/clients/tanstack-query/src/common/types.ts
Updated hook filtering logic to use ModelAllowsCreate instead of IsDelegateModel for determining which CRUD hooks to expose per model.
Test Schema & Types
tests/e2e/orm/schemas/unsupported/schema.zmodel, tests/e2e/orm/schemas/unsupported/schema.ts, tests/e2e/orm/schemas/unsupported/models.ts, tests/e2e/orm/schemas/unsupported/input.ts
Added comprehensive test schema with Item, GeoRecord, GeoParent, and GeoRecordWithDefault models featuring required unsupported XML fields, with and without defaults. Generated corresponding TypeScript type aliases.
Test Coverage
tests/e2e/orm/client-api/unsupported.test-d.ts, tests/e2e/orm/client-api/unsupported.test.ts
Added type-level and runtime tests validating unsupported field exclusion from results, filters, selects, and create/update payloads; tests confirm operation availability based on unsupported field requirements and defaults.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A cottontail's refrain on filtering fields:

Unsupported fields now caught with care,
No more delegates—just what's fair!
Models create when defaults align,
Types and runtime in sweet design.
A schema refined, both safe and true! 🌿✨

🚥 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 title clearly and specifically describes the main change: excluding Unsupported fields from the ORM client, which is the primary objective of this comprehensive refactor.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/exclude-unsupported-fields

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant