Skip to content

merge dev to main (v3.5.4)#2546

Merged
ymc9 merged 4 commits intomainfrom
dev
Apr 3, 2026
Merged

merge dev to main (v3.5.4)#2546
ymc9 merged 4 commits intomainfrom
dev

Conversation

@ymc9
Copy link
Copy Markdown
Member

@ymc9 ymc9 commented Apr 3, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Improved filter handling to properly treat undefined values and empty objects in logical operations.
    • Enhanced relation disconnect and delete input processing.
    • Fixed type support for delegate models with discriminated unions.
  • Tests

    • Added test coverage for undefined value handling in filter operations.
  • Chores

    • Updated version to 3.5.4 across all packages.

ymc9 and others added 4 commits April 2, 2026 09:35
…on files (#2544)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: ymc9 <104139426+ymc9@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
…OR filter (#2528)

Co-authored-by: ymc9 <104139426+ymc9@users.noreply.github.com>
@claude
Copy link
Copy Markdown
Contributor

claude bot commented Apr 3, 2026

Claude finished @ymc9's task —— View job


PR Review: merge dev to main (v3.5.4)

This PR merges development changes for version 3.5.4, containing mostly version bumps along with some substantive bug fixes and enhancements.

Code Review Summary

✅ Positive Aspects

1. Type System Improvements (crud-types.ts)

  • Enhanced delegate model handling with proper discriminated unions
  • Added robust type guards and recursion limits (lines 160-181) to prevent infinite loops
  • Improved type safety with better null handling and conditional types

2. Query Processing Enhancements (base-dialect.ts)

  • Better handling of empty filter normalization (lines 265-298) - properly handles empty arrays in logical operators
  • Improved null safety in filter processing
  • Enhanced cursor pagination implementation

3. Utility Functions (object-utils.ts)

  • Added isEmptyObject helper function for better object validation
  • Clean, focused utility functions with proper type definitions

4. Policy Engine Fixes (expression-transformer.ts)

  • Critical fix on line 1026: proper handling of terminal field access in relation chains
  • Better error handling for collection predicates
  • Improved binding scope management

🔍 Areas of Concern

1. Performance Considerations

  • Complex Type Recursion: The delegate union type computation in crud-types.ts (lines 146-181) could be expensive for deeply nested inheritance hierarchies
  • Query Optimization: The new filter normalization logic adds overhead to every query operation
  • Memory Usage: Deep object traversal in policy expressions may impact memory for large schemas

2. Potential Edge Cases

  • Empty Filter Handling: The normalization in buildCompositeFilter removes objects with only undefined values, but this might affect intentional undefined comparisons
  • Cursor Pagination: Complex cursor logic could fail with custom sort orders or nullable fields
  • Type Inference: The recursion depth limit of 10 in delegate types might be insufficient for some inheritance patterns

3. Security & Validation

  • Input Sanitization: Filter processing doesn't validate against potential injection attacks through complex nested objects
  • Access Control: Policy expression evaluation could potentially expose internal schema details through error messages

🐛 Minor Issues

1. Code Quality

// Line 265-272 in base-dialect.ts - could be simplified
const normalizedPayload = enumerate(payload).filter((el) => {
    if (typeof el === 'object' && el !== null && !Array.isArray(el)) {
        const entries = Object.entries(el);
        return entries.some(([, v]) => v !== undefined);
    } else {
        return true;
    }
});

This logic could be extracted to a utility function for better readability.

2. Type Safety
The isEmptyObject function in object-utils.ts should use more specific typing:

export function isEmptyObject(x: unknown): x is Record<string, never> {
    return isPlainObject(x) && Object.keys(x as object).length === 0;
}

📊 Test Coverage

  • Good coverage for filter operations with edge cases (empty arrays, null values)
  • Tests include database-specific behavior (SQLite case sensitivity)
  • Missing tests for the new delegate inheritance recursion limits

🔐 Security Assessment

  • No obvious security vulnerabilities
  • Input validation appears adequate for the ORM context
  • Policy expression handling maintains proper isolation

🚀 Performance Impact

  • Moderate Impact: The filter normalization adds computational overhead but provides better correctness
  • Memory: Type system improvements may increase compilation time but runtime performance should be stable
  • Database: No significant changes to generated SQL queries

Recommendations

  1. Add performance benchmarks for complex delegate inheritance scenarios
  2. Extract complex filter logic to utility functions for better maintainability
  3. Add integration tests for edge cases in the new filter normalization
  4. Document the recursion limits for delegate types in user documentation
  5. Consider caching for expensive type computations in development environments

Overall Assessment

This is a solid release that addresses several important bugs and improves type safety. The changes are well-implemented with appropriate safeguards. The code quality is high and the fixes address real user pain points.

Recommendation: ✅ Approve for merge

The benefits of the bug fixes and type improvements outweigh the minor performance considerations. The changes maintain backward compatibility while enhancing the developer experience.


@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 3, 2026

📝 Walkthrough

Walkthrough

This pull request updates the project version from 3.5.3 to 3.5.4 across all package manifests and introduces enhancements to the ORM client's filter handling, delete operations, and type system for delegate models, along with corresponding test coverage.

Changes

Cohort / File(s) Summary
Package Version Bumps
package.json, packages/auth-adapters/better-auth/package.json, packages/cli/package.json, packages/clients/client-helpers/package.json, packages/clients/tanstack-query/package.json, packages/common-helpers/package.json, packages/config/eslint-config/package.json, packages/config/typescript-config/package.json, packages/config/vitest-config/package.json, packages/create-zenstack/package.json, packages/ide/vscode/package.json, packages/language/package.json, packages/orm/package.json, packages/plugins/policy/package.json, packages/schema/package.json, packages/sdk/package.json, packages/server/package.json, packages/testtools/package.json, packages/zod/package.json, samples/orm/package.json, tests/e2e/package.json, tests/regression/package.json, tests/runtimes/.../*
Updated all package versions from 3.5.3 to 3.5.4.
ORM Delegate Union Type System
packages/orm/src/client/crud-types.ts
Introduced delegate discriminated-union logic with FlatModelResult, DelegateUnionResult, and IsGenericModel guard to enable type-safe field access through control-flow narrowing for sub-models, controlling recursion depth to prevent infinite expansion.
ORM Filter Undefined Handling
packages/orm/src/client/crud/dialects/base-dialect.ts
Updated buildCompositeFilter to normalize payloads by enumerating, filtering empty objects, and mapping through buildFilter; AND returns true() for zero filters, OR returns false(), NOT returns true(); added undefined operator value skipping in buildStandardFilter and buildStringFilter.
ORM Delete/Disconnect Operations
packages/orm/src/client/crud/operations/base.ts
Modified delete relation handling with new uniqueDelete boolean parameter, extended empty-object support for disconnect/delete inputs, normalized disconnect conditions to handle empty objects with unconditional disconnect, and adjusted delete-count validation logic.
Utility Functions
packages/orm/src/utils/object-utils.ts
Added new isEmptyObject() utility to detect plain objects with zero own enumerable keys.
Policy Plugin Documentation
packages/plugins/policy/src/expression-evaluator.ts, packages/plugins/policy/src/expression-transformer.ts
Updated JSDoc comments for ExpressionEvaluator and ExpressionTransformer classes to clarify their purpose; reformatted buildComparison call for readability.
Filter and Delegate Type Tests
tests/e2e/orm/client-api/filter.test.ts, tests/e2e/orm/client-api/find.test.ts, tests/e2e/orm/schemas/delegate/typecheck.ts
Added comprehensive test coverage for undefined value handling in logical where clauses; updated NOT: [] assertion in find tests; activated discriminated-union narrowing examples for delegate assets.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A patch so fine, version's refined,
Filters and deletes redesigned,
Delegates dance with union'd grace,
Undefined values find their place,
From 3.5.3 to .4 we climb! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.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 describes the primary action: merging the dev branch to main with version bump to 3.5.4, which is supported by the extensive version updates across all package.json files and ORM-related functionality changes in the changeset.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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

🧹 Nitpick comments (2)
packages/orm/src/client/crud/operations/base.ts (2)

2241-2270: Consider using a more explicit type for expectedDeleteCount.

The logic is correct, but using -1 as a sentinel for "no validation" is a magic number pattern. A union type or null/undefined would be more self-documenting:

Optional refactor
-        let expectedDeleteCount = -1; // -1 means no expected delete count check
+        let expectedDeleteCount: number | null = null; // null means no expected delete count check
         // ...
-        if (throwForNotFound && expectedDeleteCount >= 0 && expectedDeleteCount > (deleteResult.numAffectedRows ?? 0)) {
+        if (throwForNotFound && expectedDeleteCount !== null && expectedDeleteCount > (deleteResult.numAffectedRows ?? 0)) {

Otherwise, the refactoring correctly differentiates delete (validates count) from deleteMany (no validation), and properly handles empty objects as unconditional deletes.

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

In `@packages/orm/src/client/crud/operations/base.ts` around lines 2241 - 2270,
The code uses a magic number (-1) for expectedDeleteCount to signal "no
validation"; replace this with a clearer type (e.g., make expectedDeleteCount:
number | null and initialize to null) and update all checks that compare against
-1 to instead check for null (or undefined) so intent is explicit; update the
variable declaration and the branches that set expectedDeleteCount (the
boolean/data handling and the uniqueDelete block where it’s set to 1 or
deleteConditions.length) and any subsequent logic that reads expectedDeleteCount
(search for usages in this function) to handle the null sentinel consistently.

1155-1158: Type inconsistency: combinedWhere can be boolean but typed as Record<string, unknown>.

When where is undefined, combinedWhere is assigned true (a boolean), but the type annotation is Record<string, unknown>. This allows runtime behavior where combinedWhere is a boolean, while TypeScript believes it's always an object.

Additionally, Object.keys(combinedWhere) on line 1157 will return [] for true, which works but is semantically confusing.

Consider updating the type to reflect the actual runtime values:

Suggested change
-        let combinedWhere: Record<string, unknown> = where ?? true;
+        let combinedWhere: Record<string, unknown> | true = where ?? true;
         if (Object.keys(parentWhere).length > 0) {
-            combinedWhere = Object.keys(combinedWhere).length > 0 ? { AND: [parentWhere, combinedWhere] } : parentWhere;
+            combinedWhere = combinedWhere !== true && Object.keys(combinedWhere).length > 0 ? { AND: [parentWhere, combinedWhere] } : parentWhere;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/orm/src/client/crud/operations/base.ts` around lines 1155 - 1158,
The variable combinedWhere is currently typed as Record<string, unknown> but can
be assigned boolean (true) at runtime; change its type to Record<string,
unknown> | boolean (or unknown and narrow) and update the logic to narrow before
calling Object.keys — e.g., declare combinedWhere as Record<string, unknown> |
boolean and replace Object.keys(combinedWhere).length checks with a guarded path
that treats booleans separately (or coerce to {} when boolean) so functions like
the conditional using parentWhere and the AND merge operate on object shapes
only; update references to combinedWhere, parentWhere, and where accordingly to
avoid calling Object.keys on a boolean.
🤖 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 263-297: The current normalization maps payload entries to
normalizedFilters via buildFilter but doesn't remove no-op filters that
buildFilter may return (e.g., a true() sentinel), which lets nested
undefined-only branches turn OR/NOT into always-true/false; after calling
this.buildFilter in the normalizedFilters creation, filter out any filters that
are the no-op sentinel returned by buildFilter (compare against this.true() or
the sentinel your dialect uses) so composite combinators (.and/.or/.not) only
receive meaningful conditions; update the normalizedFilters construction (the
map over normalizedPayload) to produce only non-no-op filters before the match
on 'AND'/'OR'/'NOT'.

---

Nitpick comments:
In `@packages/orm/src/client/crud/operations/base.ts`:
- Around line 2241-2270: The code uses a magic number (-1) for
expectedDeleteCount to signal "no validation"; replace this with a clearer type
(e.g., make expectedDeleteCount: number | null and initialize to null) and
update all checks that compare against -1 to instead check for null (or
undefined) so intent is explicit; update the variable declaration and the
branches that set expectedDeleteCount (the boolean/data handling and the
uniqueDelete block where it’s set to 1 or deleteConditions.length) and any
subsequent logic that reads expectedDeleteCount (search for usages in this
function) to handle the null sentinel consistently.
- Around line 1155-1158: The variable combinedWhere is currently typed as
Record<string, unknown> but can be assigned boolean (true) at runtime; change
its type to Record<string, unknown> | boolean (or unknown and narrow) and update
the logic to narrow before calling Object.keys — e.g., declare combinedWhere as
Record<string, unknown> | boolean and replace Object.keys(combinedWhere).length
checks with a guarded path that treats booleans separately (or coerce to {} when
boolean) so functions like the conditional using parentWhere and the AND merge
operate on object shapes only; update references to combinedWhere, parentWhere,
and where accordingly to avoid calling Object.keys on a boolean.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0809f2a6-f8a6-4648-928c-e201e5875339

📥 Commits

Reviewing files that changed from the base of the PR and between 6a77077 and c6c8ad1.

📒 Files selected for processing (33)
  • package.json
  • packages/auth-adapters/better-auth/package.json
  • packages/cli/package.json
  • packages/clients/client-helpers/package.json
  • packages/clients/tanstack-query/package.json
  • packages/common-helpers/package.json
  • packages/config/eslint-config/package.json
  • packages/config/typescript-config/package.json
  • packages/config/vitest-config/package.json
  • packages/create-zenstack/package.json
  • packages/ide/vscode/package.json
  • packages/language/package.json
  • packages/orm/package.json
  • 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/utils/object-utils.ts
  • packages/plugins/policy/package.json
  • packages/plugins/policy/src/expression-evaluator.ts
  • packages/plugins/policy/src/expression-transformer.ts
  • packages/schema/package.json
  • packages/sdk/package.json
  • packages/server/package.json
  • packages/testtools/package.json
  • packages/zod/package.json
  • samples/orm/package.json
  • tests/e2e/orm/client-api/filter.test.ts
  • tests/e2e/orm/client-api/find.test.ts
  • tests/e2e/orm/schemas/delegate/typecheck.ts
  • tests/e2e/package.json
  • tests/regression/package.json
  • tests/runtimes/bun/package.json
  • tests/runtimes/edge-runtime/package.json

@ymc9 ymc9 merged commit cbf144f into main Apr 3, 2026
17 checks passed
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.

3 participants