Skip to content

Conversation

@ymc9
Copy link
Member

@ymc9 ymc9 commented Aug 13, 2025

Summary by CodeRabbit

  • New Features
    • Added support for _avg, _min, and _max in aggregate/groupBy.
    • Computed fields now work consistently in filtering, ordering, aggregation, and groupBy across dialects.
  • Bug Fixes
    • Improved reliability of field references in queries, ensuring correct results with aliases and subqueries.
  • Tests
    • Expanded coverage for computed fields across queries and aggregations.
  • Chores
    • Bumped package versions to 3.0.0-alpha.21 across the monorepo.

Copilot AI review requested due to automatic review settings August 13, 2025 03:44
@coderabbitai
Copy link

coderabbitai bot commented Aug 13, 2025

Walkthrough

Introduces a BaseCrudDialect.fieldRef method and refactors runtime code to use it across filtering, ordering, selection, and grouping. Updates aggregation utilities to support more operators and enforce exhaustiveness. Expands computed-field tests. Bumps package versions from 3.0.0-alpha.20 to 3.0.0-alpha.21 across multiple packages.

Changes

Cohort / File(s) Summary
Runtime CRUD refactor
packages/runtime/src/client/crud/dialects/base.ts, .../dialects/postgresql.ts, .../dialects/sqlite.ts, .../operations/base.ts, .../operations/group-by.ts
Adds BaseCrudDialect.fieldRef and replaces buildFieldRef usages; standardizes field references in filters, orderBy, select, joins; group-by now uses fieldRef and centralized aggregate helper.
Aggregation utility
packages/runtime/src/client/query-utils.ts
Extends aggregate() to support _avg, _min, _max; enforces exhaustive operator handling; streamlined signature.
Tests
packages/runtime/test/client-api/computed-fields.test.ts
Adds tests for computed field filtering, ordering, aggregation, and groupBy behavior on User.upperName.
Version bumps (workspace packages)
package.json, packages/cli/package.json, packages/common-helpers/package.json, packages/create-zenstack/package.json, packages/dialects/sql.js/package.json, packages/eslint-config/package.json, packages/ide/vscode/package.json, packages/language/package.json, packages/runtime/package.json, packages/sdk/package.json, packages/tanstack-query/package.json, packages/testtools/package.json, packages/typescript-config/package.json, packages/vitest-config/package.json, packages/zod/package.json
Bump version 3.0.0-alpha.20 → 3.0.0-alpha.21; no other changes.
Version bumps (samples/tests)
samples/blog/package.json, tests/e2e/package.json
Bump version 3.0.0-alpha.20 → 3.0.0-alpha.21; no other changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~18 minutes

Possibly related PRs

Poem

A rabbit taps keys with delighted flair,
fieldRef now hops from here to there.
Aggregates multiply—avg, max, min—
queries align, all tidy within.
Tests nibble greens, results align,
versions tick upward—alpha .21.
Thump, thump—ship it, done! 🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR merges development changes to main, incrementing package versions from 3.0.0-alpha.20 to 3.0.0-alpha.21 across the monorepo. The changes include version bumps, new test cases for computed fields, and improvements to field reference handling in database query operations.

  • Version increment across all packages from alpha.20 to alpha.21
  • Enhanced computed field testing with filtering, ordering, and aggregation operations
  • Refactored field reference building to use a centralized fieldRef method in dialect classes

Reviewed Changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Multiple package.json files Version bumps from 3.0.0-alpha.20 to 3.0.0-alpha.21
packages/runtime/test/client-api/computed-fields.test.ts Added comprehensive tests for computed field operations
packages/runtime/src/client/query-utils.ts Simplified aggregate function signature
packages/runtime/src/client/crud/operations/group-by.ts Refactored to use centralized field reference method
packages/runtime/src/client/crud/operations/base.ts Updated to use dialect's fieldRef method
packages/runtime/src/client/crud/dialects/*.ts Implemented fieldRef method in dialect classes

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.

@claude
Copy link

claude bot commented Aug 13, 2025

Claude finished @ymc9's task —— View job


Pull Request Review

Reviewing PR #157: merge dev to main (v3.0.0-alpha.20 → v3.0.0-alpha.21)

Todo List:

  • Analyze package.json version changes
  • Review computed field test additions
  • Examine field reference refactoring in dialect classes
  • Check core runtime operation changes
  • Review query utils simplification
  • Provide comprehensive feedback on code quality, bugs, performance, security, and test coverage

Review Summary

This PR merges development changes from alpha.20 to alpha.21, including version bumps across all packages and important improvements to computed field handling and field reference management.

Code Quality & Best Practices ✅

Strengths:

  • Clean refactoring: The centralization of field reference building into a fieldRef method in BaseCrudDialect is well-architected and improves code reusability
  • Consistent patterns: All dialect classes properly implement the new fieldRef method, maintaining architectural consistency
  • Comprehensive testing: New computed field tests cover filtering, ordering, aggregations, and type safety scenarios
  • Type safety: The computed field tests include TypeScript type checking to ensure proper nullability handling

Performance Considerations ✅

Positive aspects:

  • Centralized field references: The fieldRef method reduces code duplication and provides a single point for field reference optimization
  • Database-level computed fields: Computed fields are evaluated at the database level rather than in application code, which is optimal for performance
  • Proper aggregation handling: The groupBy operations correctly use the centralized field reference method for aggregations

No performance concerns identified.

Security Assessment ✅

Security posture:

  • No security vulnerabilities: The changes are internal refactoring and testing additions without external-facing APIs
  • Safe computed fields: The computed field implementation properly uses parameterized queries through the expression builder
  • Input validation maintained: The changes preserve existing input validation patterns

Test Coverage Assessment ✅

Strong test additions:

  • Comprehensive computed field coverage: Tests include basic functionality, filtering, ordering, aggregations, and type safety
  • Edge case testing: Tests cover both optional and non-optional computed fields
  • Type verification: TypeScript compilation tests ensure proper type inference

Potential Issues & Recommendations

Minor Concerns:

  1. packages/runtime/src/client/crud/dialects/base.ts:996-998

    • The new fieldRef method is a simple wrapper around buildFieldRef utility
    • Consider if this indirection adds value or if the utility could be used directly
  2. packages/runtime/test/client-api/computed-fields.test.ts:229

    • Line 229 uses toResolveNull() matcher - ensure this custom matcher is properly defined in the test framework

Code Quality Observations:

Excellent patterns:

  • Consistent error handling: All new code follows existing error handling patterns
  • Clean abstractions: The dialect pattern is well-maintained with proper method signatures
  • Documentation through tests: The test cases serve as excellent documentation for computed field usage

Technical Architecture

The refactoring maintains ZenStack's architectural principles:

  • Kysely integration: Proper use of Kysely expression builders for type-safe query construction
  • Dialect abstraction: Database-specific logic properly isolated in dialect classes
  • Plugin compatibility: Changes don't break the plugin architecture

Recommendation: ✅ APPROVE

This is a well-executed maintenance release that:

  • Improves code organization without breaking changes
  • Adds comprehensive test coverage for computed fields
  • Maintains high code quality standards
  • Introduces no security or performance regressions

The version bump to alpha.21 is appropriate for these improvements. The changes are ready for merge.

@ymc9 ymc9 changed the title merge dev to main merge dev to main (v3.0.0-alpha.21) Aug 13, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
packages/runtime/src/client/query-utils.ts (1)

321-329: Add explicit return type to stabilize API surface

Good addition of _avg/_min/_max and exhaustive handling. To avoid unintended type drift and preserve the function’s public contract, add an explicit return type (it used to be Expression).

Apply this diff:

-export function aggregate(eb: ExpressionBuilder<any, any>, expr: Expression<any>, op: AGGREGATE_OPERATORS) {
+export function aggregate(
+    eb: ExpressionBuilder<any, any>,
+    expr: Expression<any>,
+    op: AGGREGATE_OPERATORS,
+): Expression<any> {
packages/runtime/src/client/crud/dialects/base.ts (2)

736-747: Remove redundant _count orderBy branch (now unreachable)

The general aggregation branch above already handles '_count' (and continues the loop). This specific case is now dead code and can be removed to reduce confusion.

Apply this diff to remove the special-casing:

-                switch (field) {
-                    case '_count': {
-                        invariant(value && typeof value === 'object', 'invalid orderBy value for field "_count"');
-                        for (const [k, v] of Object.entries<string>(value)) {
-                            invariant(v === 'asc' || v === 'desc', `invalid orderBy value for field "${field}"`);
-                            result = result.orderBy(
-                                (eb) => eb.fn.count(this.fieldRef(model, k, eb, modelAlias)),
-                                sql.raw(this.negateSort(v, negated)),
-                            );
-                        }
-                        continue;
-                    }
-                    default:
-                        break;
-                }
+                // no-op: aggregations handled above

755-770: Avoid building expressions with a detached expressionBuilder in orderBy

Prefer the callback form of orderBy to build expressions with the query’s own ExpressionBuilder. This keeps expression construction consistent and avoids unexpected builder scoping issues.

Apply this diff:

-                    const fieldRef = this.fieldRef(model, field, expressionBuilder(), modelAlias);
-                    if (value === 'asc' || value === 'desc') {
-                        result = result.orderBy(fieldRef, this.negateSort(value, negated));
-                    } else if (
+                    if (value === 'asc' || value === 'desc') {
+                        result = result.orderBy(
+                            (eb) => this.fieldRef(model, field, eb, modelAlias),
+                            this.negateSort(value, negated),
+                        );
+                    } else if (
                         value &&
                         typeof value === 'object' &&
                         'nulls' in value &&
                         'sort' in value &&
                         (value.sort === 'asc' || value.sort === 'desc') &&
                         (value.nulls === 'first' || value.nulls === 'last')
                     ) {
                         result = result.orderBy(
-                            fieldRef,
+                            (eb) => this.fieldRef(model, field, eb, modelAlias),
                             sql.raw(`${this.negateSort(value.sort, negated)} nulls ${value.nulls}`),
                         );
                     }

And remove the now-unused import:

- import { expressionBuilder, sql, type SelectQueryBuilder } from 'kysely';
+ import { sql, type SelectQueryBuilder } from 'kysely';
packages/runtime/test/client-api/computed-fields.test.ts (1)

40-90: Great coverage for computed fields; consider adding numeric aggregations

Nice additions covering where/orderBy/negative take/aggregate/groupBy using a computed field. To fully exercise the expanded aggregations, consider adding tests for _avg/_sum/_min on a numeric computed field (e.g., nameLength: Int @computed as LENGTH(name)) and ordering by those aggregates.

I can add a minimal numeric-computed-field setup and corresponding tests if you’d like.

packages/runtime/src/client/crud/dialects/sqlite.ts (1)

202-202: Unnecessary type casting to ArgsType.

The type cast as ArgsType on this line appears to be redundant since this.fieldRef should already return a type compatible with ArgsType. The same pattern on line 173 doesn't use this cast.

Consider removing the unnecessary type cast for consistency:

-return [sql.lit(field), this.fieldRef(relationModel, field, eb) as ArgsType];
+return [sql.lit(field), this.fieldRef(relationModel, field, eb)];
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b36641 and c28fe54.

📒 Files selected for processing (24)
  • package.json (1 hunks)
  • packages/cli/package.json (1 hunks)
  • packages/common-helpers/package.json (1 hunks)
  • packages/create-zenstack/package.json (1 hunks)
  • packages/dialects/sql.js/package.json (1 hunks)
  • packages/eslint-config/package.json (1 hunks)
  • packages/ide/vscode/package.json (1 hunks)
  • packages/language/package.json (1 hunks)
  • packages/runtime/package.json (1 hunks)
  • packages/runtime/src/client/crud/dialects/base.ts (8 hunks)
  • packages/runtime/src/client/crud/dialects/postgresql.ts (2 hunks)
  • packages/runtime/src/client/crud/dialects/sqlite.ts (2 hunks)
  • packages/runtime/src/client/crud/operations/base.ts (3 hunks)
  • packages/runtime/src/client/crud/operations/group-by.ts (5 hunks)
  • packages/runtime/src/client/query-utils.ts (1 hunks)
  • packages/runtime/test/client-api/computed-fields.test.ts (1 hunks)
  • packages/sdk/package.json (1 hunks)
  • packages/tanstack-query/package.json (1 hunks)
  • packages/testtools/package.json (1 hunks)
  • packages/typescript-config/package.json (1 hunks)
  • packages/vitest-config/package.json (1 hunks)
  • packages/zod/package.json (1 hunks)
  • samples/blog/package.json (1 hunks)
  • tests/e2e/package.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
{packages,samples,tests}/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

Packages are located in packages/, samples/, and tests/

Files:

  • packages/eslint-config/package.json
  • packages/language/package.json
  • packages/ide/vscode/package.json
  • packages/testtools/package.json
  • packages/common-helpers/package.json
  • samples/blog/package.json
  • packages/typescript-config/package.json
  • packages/zod/package.json
  • packages/vitest-config/package.json
  • packages/cli/package.json
  • packages/tanstack-query/package.json
  • packages/runtime/src/client/crud/dialects/sqlite.ts
  • packages/sdk/package.json
  • packages/runtime/package.json
  • tests/e2e/package.json
  • packages/runtime/src/client/crud/operations/base.ts
  • packages/create-zenstack/package.json
  • packages/dialects/sql.js/package.json
  • packages/runtime/src/client/query-utils.ts
  • packages/runtime/src/client/crud/dialects/postgresql.ts
  • packages/runtime/src/client/crud/dialects/base.ts
  • packages/runtime/test/client-api/computed-fields.test.ts
  • packages/runtime/src/client/crud/operations/group-by.ts
tests/e2e/**

📄 CodeRabbit Inference Engine (CLAUDE.md)

E2E tests are in tests/e2e/ directory

Files:

  • tests/e2e/package.json
🧠 Learnings (1)
📚 Learning: 2025-08-04T08:43:33.161Z
Learnt from: CR
PR: zenstackhq/zenstack-v3#0
File: CLAUDE.md:0-0
Timestamp: 2025-08-04T08:43:33.161Z
Learning: `zenstack generate` compiles ZModel to TypeScript schema (`schema.ts`)

Applied to files:

  • packages/language/package.json
🧬 Code Graph Analysis (4)
packages/runtime/src/client/crud/operations/base.ts (1)
packages/runtime/src/client/crud/dialects/base.ts (1)
  • fieldRef (996-998)
packages/runtime/src/client/query-utils.ts (2)
packages/sdk/src/schema/expression.ts (1)
  • Expression (1-10)
packages/runtime/src/client/constants.ts (2)
  • AGGREGATE_OPERATORS (29-29)
  • AGGREGATE_OPERATORS (30-30)
packages/runtime/src/client/crud/dialects/base.ts (2)
packages/runtime/src/client/query-utils.ts (2)
  • aggregate (321-329)
  • buildFieldRef (157-179)
packages/runtime/src/client/constants.ts (2)
  • AGGREGATE_OPERATORS (29-29)
  • AGGREGATE_OPERATORS (30-30)
packages/runtime/src/client/crud/operations/group-by.ts (2)
packages/runtime/src/client/crud/dialects/base.ts (1)
  • fieldRef (996-998)
packages/runtime/src/client/query-utils.ts (1)
  • aggregate (321-329)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build-test (20.x)
  • GitHub Check: claude-review
🔇 Additional comments (35)
packages/create-zenstack/package.json (1)

3-3: All package.json versions are consistent at 3.0.0-alpha.21

Verified via script—no mismatches found across all packages. Metadata-only bump; no further changes needed.

packages/sdk/package.json (1)

3-3: LGTM: SDK manifest version bumped as part of coordinated release

Looks consistent with the monorepo-wide alpha.21 bump; no other manifest changes.

packages/language/package.json (1)

4-4: LGTM: language package version updated

Metadata-only change; build and export config remain unchanged.

packages/zod/package.json (1)

3-3: LGTM: zod package version bump

Private package, metadata-only; aligns with the release.

packages/cli/package.json (1)

6-6: LGTM: CLI package version bump

No behavioral changes; aligns with other packages for alpha.21 release.

packages/tanstack-query/package.json (1)

3-3: LGTM: Version bump is consistent with the release train.
No other changes in this manifest; dependency and peer ranges remain intact.

packages/eslint-config/package.json (1)

3-3: LGTM: Metadata-only version bump.
No config or dependency changes; safe to merge.

packages/common-helpers/package.json (1)

3-3: LGTM: Version updated to alpha.21.
No export or script changes; aligns with the monorepo rollout.

package.json (2)

3-3: LGTM: Root version bump to alpha.21.
Matches the repo-wide version update.


3-3: No stale references to 3.0.0-alpha.20 remain
Ran the verification script and confirmed:

  • rg found zero occurrences of 3.0.0-alpha.20
  • All package.json files list "version": "3.0.0-alpha.21"
samples/blog/package.json (1)

3-3: LGTM: Sample app version bumped.
No impact to scripts or workspace dependencies.

packages/ide/vscode/package.json (1)

4-4: Version bump looks good

Semver prerelease bump only; no other changes. Safe to merge.

packages/typescript-config/package.json (1)

3-3: Version bump looks good

Metadata-only change; no behavioral impact.

packages/testtools/package.json (1)

3-3: Version bump looks good

No functional changes; consistent with repo-wide bump.

packages/runtime/package.json (2)

3-3: Version bump looks good

Aligned with the runtime changes introduced elsewhere in the PR.


3-3: Repo-wide versions and workspace dependencies are consistent

All package.json files have been updated to 3.0.0-alpha.21, and no @zenstackhq/* dependencies are hard-pinned to a non-workspace version.

tests/e2e/package.json (1)

3-3: Version bump looks good

E2E package version aligned with the monorepo bump.

packages/vitest-config/package.json (1)

4-4: Version bump aligns with the release train

Monorepo version bump to 3.0.0-alpha.21 looks consistent and isolated. No concerns.

packages/dialects/sql.js/package.json (1)

3-3: Version bump only; safe change

Package version updated to 3.0.0-alpha.21 with no other alterations. Looks good.

packages/runtime/src/client/crud/dialects/base.ts (4)

98-104: Centralized fieldRef usage in filters is correct

Switching to this.fieldRef respects originModel and unlocks computed-field support across filter paths. Good improvement.


728-731: OrderBy aggregation now properly leverages fieldRef

Using aggregate(eb, this.fieldRef(...)) ensures ordering by computed or aliased fields works across dialects. Looks good.


869-869: Computed-field selection via fieldRef is correct

Selecting computed fields with this.fieldRef(...).as(field) ensures parity with non-computed fields and honors aliases. Good change.


996-999: New fieldRef helper centralizes field reference construction

Exposing fieldRef on the dialect and delegating to buildFieldRef improves consistency and encapsulation. Good abstraction.

packages/runtime/src/client/crud/operations/base.ts (3)

189-189: LGTM! Consistent use of dialect.fieldRef for distinct field references.

The change correctly uses the new centralized dialect.fieldRef API for building field references in the distinct field selection, aligning with the broader refactoring pattern across the codebase.


1267-1267: LGTM! Proper migration to dialect.fieldRef for incremental updates.

The change correctly uses dialect.fieldRef for building field references in incremental update operations, maintaining consistency with the new API pattern.


1290-1290: LGTM! Consistent use of dialect.fieldRef for scalar list updates.

The change properly uses dialect.fieldRef for building field references in scalar list update operations, aligning with the centralized field reference API.

packages/runtime/src/client/crud/dialects/sqlite.ts (1)

173-173: LGTM! Consistent migration to fieldRef in SQLite dialect.

The change correctly replaces buildFieldRef with this.fieldRef for scalar field references in the SQLite dialect, maintaining consistency with the centralized field reference API introduced in the base dialect.

packages/runtime/src/client/crud/dialects/postgresql.ts (2)

229-229: LGTM! Proper migration to fieldRef in PostgreSQL dialect.

The change correctly replaces buildFieldRef with this.fieldRef for scalar field references, maintaining consistency with the centralized field reference API.


252-252: LGTM! Consistent use of fieldRef for field selection.

The change properly uses this.fieldRef for building field references in the select clause, aligning with the new API pattern.

packages/runtime/src/client/crud/operations/group-by.ts (6)

1-1: LGTM! Appropriate imports for the new field reference pattern.

The addition of expressionBuilder and aggregate imports properly supports the new dialect-driven field reference approach.

Also applies to: 4-4


47-47: LGTM! Well-designed local helper for field references.

The fieldRef helper function provides a clean abstraction for referencing fields from the subquery alias $sub, properly utilizing the new dialect API.


51-51: LGTM! Consistent use of fieldRef for groupBy clause.

The change correctly maps all groupBy fields through the fieldRef helper, ensuring consistent field referencing from the subquery.


64-64: LGTM! Proper use of fieldRef for field selection.

The change correctly uses the fieldRef helper for selecting grouped-by fields, maintaining consistency with the new field reference pattern.


82-82: LGTM! Consistent use of fieldRef for count operations.

The change properly uses the fieldRef helper for per-field count operations, aligning with the new API pattern.


97-97: LGTM! Excellent unification of aggregation operations.

The change effectively consolidates all aggregation operations (_sum, _avg, _max, _min) through the new aggregate utility function, improving code maintainability and ensuring exhaustive handling of aggregate operators.

@ymc9 ymc9 added this pull request to the merge queue Aug 13, 2025
Merged via the queue into main with commit c10e48f Aug 13, 2025
8 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.

2 participants