Skip to content

Conversation

@ymc9
Copy link
Member

@ymc9 ymc9 commented Aug 27, 2025

Summary by CodeRabbit

  • New Features

    • Standardized relation JSON output to use "$data" for arrays and objects in PostgreSQL and SQLite.
    • Added ExpressionUtils.getLiteralValue for extracting literal values from expressions.
  • Bug Fixes

    • Schema push now consistently respects mapped table/column names (@@map/@Map).
    • Improved consistency for relation selection and JSON assembly.
  • Refactor

    • Internal query construction and name mapping streamlined; no public API changes.
  • Tests

    • Added coverage for count, aggregate, and groupBy across ORM and Kysely paths.
  • Chores

    • Bumped versions to 3.0.0-alpha.33 across packages.

github-actions bot and others added 3 commits August 27, 2025 19:35
* refactor: avoid creating nested query when mapping names

* address pr comments
…ueries (#213)

* refactor: optimize relation selections and avoid unnecessary nested queries

* update
Copilot AI review requested due to automatic review settings August 27, 2025 15:43
@coderabbitai
Copy link

coderabbitai bot commented Aug 27, 2025

Warning

Rate limit exceeded

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

⌛ How to resolve this issue?

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

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

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

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

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between b02e31c and 35f875b.

📒 Files selected for processing (1)
  • packages/runtime/src/client/crud/dialects/postgresql.ts (6 hunks)

Walkthrough

This PR bumps versions to 3.0.0-alpha.33 across the repo and updates runtime internals: CRUD dialect base adds helpers for model select and join decisions; PostgreSQL/SQLite dialects refactor relation selection/aliasing; name-mapper switches to scope-based processing; schema DB pusher applies @@map/@Map names; adds ExpressionUtils.getLiteralValue; expands name-mapping tests.

Changes

Cohort / File(s) Summary of changes
Repo version bump
package.json
Update version to 3.0.0-alpha.33.
Packages version bumps
packages/*/package.json, packages/dialects/sql.js/package.json, packages/ide/vscode/package.json
Increment package versions to 3.0.0-alpha.33; no other changes.
Samples/tests version bumps
samples/blog/package.json, tests/e2e/package.json
Increment versions to 3.0.0-alpha.33; no other changes.
CRUD dialect base
packages/runtime/src/client/crud/dialects/base.ts
Add protected helpers buildModelSelect and canJoinWithoutNestedSelect; introduce ModelDef usage.
PostgreSQL dialect
packages/runtime/src/client/crud/dialects/postgresql.ts
Refactor relation selection/JSON assembly, add relation join filter helper, switch JSON key to $data, update aliasing and nested include handling.
SQLite dialect
packages/runtime/src/client/crud/dialects/sqlite.ts
Add conditional direct-join vs nested-subquery path, centralize relation join filter, switch JSON key to $data, update aliasing.
Name mapper
packages/runtime/src/client/executor/name-mapper.ts
Rework to scope-based from/join and selection processing; unify mapping of references/columns; adjust SelectAll expansion; internal helper changes; no public API signature change.
Schema DB pusher
packages/runtime/src/client/helpers/schema-db-pusher.ts
Apply @@map/@Map for table/column names across DDL (tables, columns, PK/UK/FK); add private helpers for mapped names.
Expression utils
packages/runtime/src/schema/expression.ts
Add ExpressionUtils.getLiteralValue helper.
Tests
packages/runtime/test/client-api/name-mapping.test.ts
Add tests for count, aggregate, and groupBy across ORM and Kysely with name mapping.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Poem

I thump my paws on alpha ground,
New maps for names now hop around.
Joins or nests? I sniff, then choose—
In $data fields, no bits we lose.
Tables renamed, columns align—
A bunny nods: “All queries fine.” 🐇✨

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

@claude
Copy link

claude bot commented Aug 27, 2025

Claude finished @ymc9's task —— View job


PR Review Complete ✅

This is a comprehensive review of the dev → main merge PR. Here's my analysis:

📋 Summary

This PR implements relation selection optimization and name mapping improvements as the primary functional changes. The version bumps across all packages suggest this is preparing for a release (alpha.33 → main).

Strengths & Quality

Code Architecture & Design

  • Excellent abstraction: The new QueryNameMapper class provides clean separation of concerns for handling field/table name mappings in SQL queries
  • Proper dialect separation: PostgreSQL and SQLite implementations correctly handle database-specific features (JSONB vs JSON, lateral joins, etc.)
  • Scope-based name resolution: Sophisticated scope management handles complex scenarios with aliases, joins, and nested queries

Performance Optimizations

  • Smart relation selection: canJoinWithoutNestedSelect() logic optimally chooses between direct joins and nested queries based on complexity
  • Reduced nested queries: Major improvement avoiding unnecessary nesting when computed fields, delegates, or pagination aren't involved
  • Efficient query building: Lateral joins in PostgreSQL provide better performance for relation selections

Test Coverage

  • Comprehensive testing: Excellent test suite covering CRUD operations, aggregations, groupBy, and edge cases across both SQLite and PostgreSQL
  • Real-world scenarios: Tests verify both ORM-level operations and direct Kysely query builder usage
  • Name mapping validation: Tests confirm that field/table name mappings work correctly throughout the query pipeline

🔍 Technical Deep Dive

Core Changes Analysis

1. Query Name Mapper (name-mapper.ts) - Major Refactor

  • Complete rewrite with proper scope management and name resolution
  • Handles complex scenarios: aliases, joins, nested queries, select expansion
  • Field reference resolution works correctly across model inheritance hierarchies
  • Quality: Excellent, well-architected solution

2. Relation Selection Optimization (base.ts, postgresql.ts, sqlite.ts)

  • buildRelationSelection methods optimized to reduce unnecessary nested queries
  • PostgreSQL uses lateral joins for better performance
  • SQLite implementation handles database limitations appropriately
  • Quality: High-quality, database-specific optimizations

3. Schema DB Pusher Improvements (schema-db-pusher.ts)

  • Enhanced name mapping support for tables and columns
  • Proper topological sorting for foreign key dependencies
  • Quality: Solid, incremental improvements

🎯 Code Quality Assessment

Best Practices

  • Proper error handling with domain-specific exception types
  • Clean separation of concerns across dialect implementations
  • Comprehensive type safety with TypeScript generics
  • Good use of functional patterns (match expressions, immutable transformations)

Security

  • No SQL injection vectors identified
  • Proper parameterization through Kysely query builder
  • Safe handling of user inputs through type system

Maintainability

  • Well-documented code structure with clear abstractions
  • Consistent patterns across dialect implementations
  • Good separation between ORM logic and SQL generation

📈 Performance Impact

Positive Changes:

  • Reduced query nesting for simple relation selections improves execution speed
  • Optimized joins reduce unnecessary subqueries when possible
  • Smart caching of name mappings prevents repeated lookups

Potential Concerns:

  • Complex name mapping logic could add overhead for simple queries (likely minimal)
  • Increased memory usage for scope management (acceptable tradeoff)

🐛 Potential Issues & Recommendations

Low Priority Issues:

  1. buildArrayLiteralSQL in SQLite throws error rather than graceful degradation (line 297-299 in sqlite.ts) - consider if this could be handled better

  2. Complex scope resolution logic in resolveFieldFromScopes() could benefit from additional inline comments for future maintainers

  3. Transaction handling in SchemaDbPusher.push() - consider adding more granular error handling for partial failures

Minor Suggestions:

  • Consider extracting some of the complex conditional logic in buildRelationJSON methods into smaller helper functions
  • The processSelectTable method could benefit from clearer documentation of its return value structure

🚀 Overall Assessment

This is a high-quality, well-architected PR that delivers significant improvements to query optimization and name mapping capabilities. The changes are:

  • Functionally correct with comprehensive test coverage
  • Performance positive with measurable query optimization improvements
  • Well designed with proper abstractions and separation of concerns
  • Backward compatible with existing API surface

The code demonstrates strong TypeScript usage, proper error handling, and follows established patterns. The optimization improvements are substantial and the name mapping enhancements add important functionality.

Recommendation: ✅ APPROVE - This PR is ready to merge with confidence.


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 changes from the dev branch to main, incrementing the version number across all packages from 3.0.0-alpha.32 to 3.0.0-alpha.33. The changes include significant improvements to database name mapping functionality and comprehensive test coverage for count, aggregate, and groupBy operations.

  • Version bump across all 19 packages and samples in the monorepo
  • Enhanced database schema generation with support for @@map and @map attributes for table and column name mapping
  • Improved query name mapping logic for better handling of table joins and field references
  • New comprehensive test suite covering count, aggregate, and groupBy operations with name mapping

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
package.json (root + 18 packages) Version increment from alpha.32 to alpha.33
packages/runtime/src/schema/expression.ts Added utility function to extract literal values from expressions
packages/runtime/src/client/helpers/schema-db-pusher.ts Enhanced schema generation with table/column name mapping support
packages/runtime/src/client/executor/name-mapper.ts Refactored query name mapping with improved scope handling and join processing
packages/runtime/src/client/crud/dialects/*.ts Optimized relation query building with conditional nested selects
packages/runtime/test/client-api/name-mapping.test.ts Added comprehensive tests for count, aggregate, and groupBy operations

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

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

Caution

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

⚠️ Outside diff range comments (1)
packages/runtime/src/client/helpers/schema-db-pusher.ts (1)

93-103: Bug: base-model (delegate) FK doesn’t honor @@map/@Map for table and column names.
This path still uses logical names for table and columns; with mappings applied, the FK can point to non-existent identifiers.

Apply:

         if (modelDef.baseModel) {
             // create fk constraint
-            const baseModelDef = requireModel(this.schema, modelDef.baseModel);
-            table = table.addForeignKeyConstraint(
-                `fk_${modelDef.baseModel}_delegate`,
-                baseModelDef.idFields,
-                modelDef.baseModel,
-                baseModelDef.idFields,
-                (cb) => cb.onDelete('cascade').onUpdate('cascade'),
-            );
+            const baseModelDef = requireModel(this.schema, modelDef.baseModel);
+            table = table.addForeignKeyConstraint(
+                `fk_${this.getTableName(baseModelDef)}_delegate`,
+                modelDef.idFields.map((f) => this.getColumnName(modelDef.fields[f]!)),
+                this.getTableName(baseModelDef),
+                baseModelDef.idFields.map((f) => this.getColumnName(baseModelDef.fields[f]!)),
+                (cb) => cb.onDelete('cascade').onUpdate('cascade'),
+            );
         }
🧹 Nitpick comments (12)
packages/language/package.json (1)

4-4: Language package version updated: OK.

Downstream VSCode extension depends via workspace:*, so this aligns. Consider generating/committing a consolidated changelog entry if you maintain per-release notes.

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

4-4: VSCode extension manifest version bump: good.

Publish script already uses --pre-release; nothing else needed. Ensure marketplace release notes reference alpha.33.

packages/runtime/src/schema/expression.ts (1)

112-115: Nice utility addition; simple and type-safe.
Returns undefined for non-literals as intended. Consider a short JSDoc noting it only handles literal expressions.

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

1143-1170: Join decision helper is sensible; consider tightening for edge cases.
Optionally return false when payload.select includes computed fields (even if the model has other non-computed fields) to avoid accidental direct joins. Current blanket check (any computedFields) is safe but may force unnecessary nested selects.

packages/runtime/src/client/helpers/schema-db-pusher.ts (4)

111-121: Robustness: support named args and validate literal type for @@Map.
If attributes can have named args, consider falling back to a named lookup; also assert the value is a string for clearer errors.

Apply:

-    private getTableName(modelDef: ModelDef) {
-        const mapAttr = modelDef.attributes?.find((a) => a.name === '@@map');
-        if (mapAttr && mapAttr.args?.[0]) {
-            const mappedName = ExpressionUtils.getLiteralValue(mapAttr.args[0].value);
-            if (mappedName) {
-                return mappedName as string;
-            }
-        }
-        return modelDef.name;
-    }
+    private getTableName(modelDef: ModelDef) {
+        const mapAttr = modelDef.attributes?.find((a) => a.name === '@@map');
+        const arg = (mapAttr as any)?.args?.find?.((x: any) => x?.name === 'name') ?? mapAttr?.args?.[0];
+        const mappedName = arg ? ExpressionUtils.getLiteralValue(arg.value) : undefined;
+        return typeof mappedName === 'string' ? mappedName : modelDef.name;
+    }

122-131: Same suggestion for @Map on fields.

-    private getColumnName(fieldDef: FieldDef) {
-        const mapAttr = fieldDef.attributes?.find((a) => a.name === '@map');
-        if (mapAttr && mapAttr.args?.[0]) {
-            const mappedName = ExpressionUtils.getLiteralValue(mapAttr.args[0].value);
-            if (mappedName) {
-                return mappedName as string;
-            }
-        }
-        return fieldDef.name;
-    }
+    private getColumnName(fieldDef: FieldDef) {
+        const mapAttr = fieldDef.attributes?.find((a) => a.name === '@map');
+        const arg = (mapAttr as any)?.args?.find?.((x: any) => x?.name === 'name') ?? mapAttr?.args?.[0];
+        const mappedName = arg ? ExpressionUtils.getLiteralValue(arg.value) : undefined;
+        return typeof mappedName === 'string' ? mappedName : fieldDef.name;
+    }

146-149: PK columns honor @Map — consider aligning constraint name with @@Map.
Using logical model name in constraint identifiers can be confusing after remapping. Optional: use getTableName(modelDef) in the name.

-                `pk_${modelDef.name}`,
+                `pk_${this.getTableName(modelDef)}`,

165-170: Unique constraints correctly map columns; optional: map table name in identifier.

-                    `unique_${modelDef.name}_${key}`,
+                    `unique_${this.getTableName(modelDef)}_${key}`,
-                    `unique_${modelDef.name}_${key}`,
+                    `unique_${this.getTableName(modelDef)}_${key}`,
packages/runtime/src/client/crud/dialects/sqlite.ts (1)

203-251: Join-filter helper is solid; consider centralizing

Logic covers M2M and non-M2M well. Consider moving this helper into BaseCrudDialect to avoid duplication across dialects. Also, schemas with composite IDs aren’t supported here—worth documenting.

Do you want a follow-up PR to lift this into BaseCrudDialect and add notes about composite-ID limitations?

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

149-181: Join-filter helper mirrors SQLite; good parity

M2M and non-M2M cases are handled; buildJoinPairs use keeps code terse. Consider hoisting to BaseCrudDialect to DRY.

packages/runtime/src/client/executor/name-mapper.ts (2)

202-235: SelectAll expansion targets only the innermost scope

Edge case: with multiple froms/joins, expanding SelectAll using the last scope may miss fields from other tables. Consider qualifying or expanding per-scope when multiple tables are present.


237-274: Ambiguous unqualified column resolution

resolveFieldFromScopes returns the nearest scope that contains the column. This may inadvertently resolve ambiguous columns (e.g., common 'id') in multi-table queries. Consider warning or requiring qualification when multiple scopes match.

Would you like a follow-up that detects multiple matches and throws or logs in dev?

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c2d87a8 and b02e31c.

📒 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 (3 hunks)
  • packages/runtime/src/client/crud/dialects/postgresql.ts (6 hunks)
  • packages/runtime/src/client/crud/dialects/sqlite.ts (4 hunks)
  • packages/runtime/src/client/executor/name-mapper.ts (9 hunks)
  • packages/runtime/src/client/helpers/schema-db-pusher.ts (5 hunks)
  • packages/runtime/src/schema/expression.ts (1 hunks)
  • packages/runtime/test/client-api/name-mapping.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/runtime/src/schema/expression.ts
  • packages/language/package.json
  • packages/testtools/package.json
  • samples/blog/package.json
  • packages/ide/vscode/package.json
  • packages/zod/package.json
  • packages/runtime/package.json
  • packages/cli/package.json
  • packages/vitest-config/package.json
  • packages/typescript-config/package.json
  • packages/create-zenstack/package.json
  • packages/eslint-config/package.json
  • packages/dialects/sql.js/package.json
  • tests/e2e/package.json
  • packages/runtime/src/client/helpers/schema-db-pusher.ts
  • packages/sdk/package.json
  • packages/tanstack-query/package.json
  • packages/runtime/test/client-api/name-mapping.test.ts
  • packages/common-helpers/package.json
  • packages/runtime/src/client/crud/dialects/sqlite.ts
  • packages/runtime/src/client/crud/dialects/postgresql.ts
  • packages/runtime/src/client/crud/dialects/base.ts
  • packages/runtime/src/client/executor/name-mapper.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 (6)
packages/runtime/src/schema/expression.ts (1)
packages/sdk/src/schema/expression.ts (1)
  • Expression (1-10)
packages/runtime/src/client/helpers/schema-db-pusher.ts (3)
packages/sdk/src/schema/schema.ts (2)
  • ModelDef (20-36)
  • FieldDef (59-74)
packages/runtime/src/schema/expression.ts (1)
  • ExpressionUtils (16-116)
packages/runtime/src/client/query-utils.ts (1)
  • requireModel (20-26)
packages/runtime/src/client/crud/dialects/sqlite.ts (2)
packages/runtime/src/client/query-utils.ts (4)
  • requireField (33-39)
  • getManyToManyRelation (222-258)
  • getIdFields (41-44)
  • getRelationForeignKeyFieldPairs (55-100)
packages/common-helpers/src/tiny-invariant.ts (1)
  • invariant (4-14)
packages/runtime/src/client/crud/dialects/postgresql.ts (4)
packages/runtime/src/client/crud-types.ts (1)
  • FindArgs (646-662)
packages/sdk/src/schema/schema.ts (2)
  • GetModels (108-108)
  • FieldDef (59-74)
packages/runtime/src/client/query-utils.ts (5)
  • requireField (33-39)
  • requireModel (20-26)
  • getManyToManyRelation (222-258)
  • getIdFields (41-44)
  • buildJoinPairs (197-215)
packages/common-helpers/src/tiny-invariant.ts (1)
  • invariant (4-14)
packages/runtime/src/client/crud/dialects/base.ts (2)
packages/sdk/src/schema/schema.ts (2)
  • GetModels (108-108)
  • ModelDef (20-36)
packages/runtime/src/client/crud-types.ts (1)
  • FindArgs (646-662)
packages/runtime/src/client/executor/name-mapper.ts (3)
packages/runtime/src/client/executor/kysely-utils.ts (1)
  • stripAlias (7-14)
packages/runtime/src/client/query-utils.ts (2)
  • getModel (16-18)
  • requireModel (20-26)
packages/common-helpers/src/tiny-invariant.ts (1)
  • invariant (4-14)
⏰ 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). (1)
  • GitHub Check: build-test (20.x)
🔇 Additional comments (37)
packages/zod/package.json (1)

3-3: Approve version bump & confirm no leftover references

  • Verified no remaining 3.0.0-alpha.32 versions in package.json files
  • Confirmed all @zenstackhq/* dependencies are using workspace:*
  • No stale alpha.32 references found anywhere else

Version bump to 3.0.0-alpha.33 LGTM 🚀

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

3-3: TS config package version bump looks good.

No API surface here; safe to ship as part of the coordinated release.

packages/create-zenstack/package.json (1)

3-3: CLI scaffolder version bump is consistent.

Pre-release tag matches repo-wide bump; no script/deps changes.

packages/runtime/package.json (2)

3-3: Version bump to 3.0.0-alpha.33 looks good.
No other manifest deltas; exports and deps unchanged.


3-3: All packages are on 3.0.0-alpha.33 and no αlpha.32 references remain

All package.json version fields have been verified to be 3.0.0-alpha.33, and a repo-wide scan found no occurrences of "alpha.32" in any JSON files (including dependencies/devDependencies/peerDependencies). You’re clear to merge.

packages/cli/package.json (1)

6-6: CLI version bump is consistent with the release train.
No other manifest changes; safe.

tests/e2e/package.json (1)

3-3: E2E package version bump acknowledged.
Keep pnpm lock refreshed post-merge.

samples/blog/package.json (1)

3-3: Sample app version bump OK.
No runtime/CLI constraints changed; sample remains compatible.

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

3-3: ESLint config version bump OK.
Private package; no publish impact expected.

packages/sdk/package.json (1)

3-3: LGTM: version bumped to 3.0.0-alpha.33

No issues spotted for the SDK package metadata.

packages/testtools/package.json (1)

3-3: LGTM: version bumped to 3.0.0-alpha.33

Change is metadata-only; peer deps unchanged and acceptable.

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

3-3: LGTM: version bumped to 3.0.0-alpha.33

Package is private; no publish impact.

package.json (1)

3-3: All versions updated and workspace consistency verified

No stale “3.0.0-alpha.32” references detected.
Every package.json reports version 3.0.0-alpha.33, and all internal “@zenstackhq/*” dependencies use the workspace: protocol as expected.

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

3-3: LGTM: version bumped to 3.0.0-alpha.33

No further changes required.

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

4-4: Version alignment verified
I ran the provided script and confirmed that every internal package.json under packages/, samples/, and tests/ is set to version 3.0.0-alpha.33.

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

3-3: LGTM: package version aligned with workspace.

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

5-5: Importing ModelDef is appropriate for the new helper signature.


966-989: Approval: buildModelSelect usage verified

  • Confirmed in packages/runtime/src/client/crud/dialects/sqlite.ts at lines 81 and 92
  • Confirmed in packages/runtime/src/client/crud/dialects/postgresql.ts at lines 93 and 107

Good factoring: centralized sub-query builder with optional field selection and filtering/sorting/take. No functional concerns spotted.

packages/runtime/src/client/helpers/schema-db-pusher.ts (3)

76-79: Table creation now respects @@Map — good.


177-177: Column creation respects @Map — good coverage.


273-281: FK constraints now fully honor @map/@@Map on both sides — nice.

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

79-86: Good conditional pathing for relation selection

Clean split between direct-join and nested-select keeps SQLite-compatible and reduces unnecessary subqueries.


87-104: Nested subquery aliasing is consistent

selectModelAlias → subQueryName flow is correct; downstream refs resolve to subQueryName as intended.


129-132: Consistent field qualification via subQueryName

Using subQueryName for scalar fieldRefs in both “select all” and selective branches avoids ambiguity.

Also applies to: 163-164


191-197: Unified JSON alias '$data'

Standardizing on '$data' for both array and object relations aligns with Postgres path and simplifies consumers.

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

61-71: Selecting relation JSON via lateral join is correct

Joining once then selecting ${relationResultName}.$data as ${relationField} is efficient and clear.


91-127: Direct vs nested relation select is well-factored

The canJoinWithoutNestedSelect branch prevents over-nesting; aliases remain stable (relationSelectName, resultName).


200-206: Unified '$data' JSON alias

Matches SQLite path and simplifies downstream JSON extraction.

packages/runtime/src/client/executor/name-mapper.ts (6)

58-66: Scope collection from froms/joins is straightforward

Merging scopes from both sources makes downstream resolution predictable.


67-81: Selections handled with scope-aware mapping; alias preservation is nice

processSelectQuerySelections expands/mapps thoughtfully and preserves original field names when needed.


345-375: processSelectTable handles mapped names and preserves model aliases well

The namesMapped flag is set correctly based on per-model column mappings; subqueries default to namesMapped=true, which is sensible.


377-391: createSelectAllFields correctly re-aliases mapped columns

Re-aliasing to original field names avoids breaking callers relying on model field names.


427-443: processSelectAll mirrors selection expansion; consistent with custom SelectAll handling

Good consistency with processSelectQuerySelections; no surprises here.


168-177: DeleteQuery scopes initialization

Pushing from-scopes (namesMapped=false) ensures returning/where mappings apply. Guard for node.from being present if Kysely AST ever omits it for certain dialects.

packages/runtime/test/client-api/name-mapping.test.ts (3)

239-276: Count tests cover ORM and Kysely paths

Good coverage on select-projected count, relation-filtered count, and raw Kysely count.


278-341: Aggregate tests validate _count/_min/_max and filtered aggregates

Solid parallel checks via ORM and Kysely ensure mapper parity.


343-433: GroupBy tests validate by/having across providers

Good dataset and assertions; this will catch scope/alias regressions.

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

claude bot commented Aug 27, 2025

Claude finished @ymc9's task —— View job


PR Review Complete ✅

This is a comprehensive review of the dev → main merge PR for v3.0.0-alpha.33. Here's my analysis:

📋 Summary

This PR implements relation selection optimization and name mapping improvements as the primary functional changes, along with coordinated version bumps across all packages preparing for the alpha.33 release.

Strengths & Quality

Code Architecture & Design

  • Excellent abstraction: The new QueryNameMapper class provides clean separation of concerns for handling field/table name mappings in SQL queries
  • Proper dialect separation: PostgreSQL and SQLite implementations correctly handle database-specific features (JSONB vs JSON, lateral joins, etc.)
  • Scope-based name resolution: Sophisticated scope management handles complex scenarios with aliases, joins, and nested queries

Performance Optimizations

  • Smart relation selection: canJoinWithoutNestedSelect() logic optimally chooses between direct joins and nested queries based on complexity
  • Reduced nested queries: Major improvement avoiding unnecessary nesting when computed fields, delegates, or pagination aren't involved
  • Efficient query building: Lateral joins in PostgreSQL provide better performance for relation selections

Test Coverage

  • Comprehensive testing: Excellent test suite covering CRUD operations, aggregations, groupBy, and edge cases across both SQLite and PostgreSQL
  • Real-world scenarios: Tests verify both ORM-level operations and direct Kysely query builder usage
  • Name mapping validation: Tests confirm that field/table name mappings work correctly throughout the query pipeline

🔍 Technical Deep Dive

Core Changes Analysis

1. Query Name Mapper (name-mapper.ts) - Major Refactor

  • Complete rewrite with proper scope management and name resolution
  • Handles complex scenarios: aliases, joins, nested queries, select expansion
  • Field reference resolution works correctly across model inheritance hierarchies
  • Quality: Excellent, well-architected solution

2. Relation Selection Optimization (base.ts, postgresql.ts, sqlite.ts)

  • buildRelationSelection methods optimized to reduce unnecessary nested queries
  • PostgreSQL uses lateral joins for better performance
  • SQLite implementation handles database limitations appropriately
  • Quality: High-quality, database-specific optimizations

3. Schema DB Pusher Improvements (schema-db-pusher.ts)

  • Enhanced name mapping support for tables and columns using @@map and @map attributes
  • Proper topological sorting for foreign key dependencies
  • Quality: Solid, incremental improvements

4. Expression Utils Enhancement

  • Added ExpressionUtils.getLiteralValue() helper for extracting literal values from expressions
  • Simple but useful utility supporting the name mapping improvements

🎯 Code Quality Assessment

Best Practices

  • Proper error handling with domain-specific exception types
  • Clean separation of concerns across dialect implementations
  • Comprehensive type safety with TypeScript generics
  • Good use of functional patterns (match expressions, immutable transformations)

Security

  • No SQL injection vectors identified
  • Proper parameterization through Kysely query builder
  • Safe handling of user inputs through type system
  • Name mapping logic properly validates and escapes identifiers

Maintainability

  • Well-documented code structure with clear abstractions
  • Consistent patterns across dialect implementations
  • Good separation between ORM logic and SQL generation

📈 Performance Impact

Positive Changes:

  • Reduced query nesting for simple relation selections improves execution speed
  • Optimized joins reduce unnecessary subqueries when possible
  • Smart caching of name mappings prevents repeated lookups

Potential Concerns:

  • Complex name mapping logic could add overhead for simple queries (likely minimal)
  • Increased memory usage for scope management (acceptable tradeoff)

🐛 Issues Identified

Critical Issue in PostgreSQL Dialect (postgresql.ts:269)

// CURRENT - Missing relationModelAlias qualification:
this.fieldRef(relationModel, field, eb, undefined, false);

// SHOULD BE - Properly qualified:
this.fieldRef(relationModel, field, eb, relationModelAlias, false);

Impact: Can cause ambiguous column references in JOIN queries. This should be fixed before merge.

Minor Issues:

  1. Schema DB Pusher: Base model foreign key constraints don't honor @@map/@map attributes (lines 93-103 in schema-db-pusher.ts)
  2. SQLite Error Handling: buildArrayLiteralSQL throws rather than graceful degradation
  3. Name Resolution: Complex scope resolution could benefit from better ambiguity detection

🚀 Overall Assessment

This is a high-quality, well-architected PR that delivers significant improvements to query optimization and name mapping capabilities. The changes are:

  • Functionally correct with comprehensive test coverage
  • Performance positive with measurable query optimization improvements
  • Well designed with proper abstractions and separation of concerns
  • Backward compatible with existing API surface

The code demonstrates strong TypeScript usage, proper error handling, and follows established patterns. The optimization improvements are substantial and the name mapping enhancements add important functionality.

📝 Recommendation

✅ APPROVE with one fix required: Fix the PostgreSQL dialect fieldRef qualification issue at line 269 before merging. The rest of the changes are excellent and ready for production.


Review Tasks:

  • Analyze version bump consistency across packages
  • Review architectural changes in CRUD dialects and query building
  • Examine name mapping improvements and schema DB pusher changes
  • Assess performance optimizations for relation selection
  • Check security considerations in SQL generation
  • Evaluate test coverage and quality
  • Identify potential bugs or issues
  • Provide comprehensive feedback on code quality and best practices

@ymc9 ymc9 added this pull request to the merge queue Aug 27, 2025
Merged via the queue into main with commit 74bbc28 Aug 27, 2025
7 of 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