Skip to content

Conversation

@ymc9
Copy link
Member

@ymc9 ymc9 commented Jun 16, 2025

Summary by CodeRabbit

  • New Features

    • Added support for updating multiple records and returning the updated entities with the new updateManyAndReturn method.
    • Enhanced relation counting to allow more precise and filtered count selections in queries.
  • Bug Fixes

    • Improved handling of the limit option in bulk delete operations to ensure correct behavior when deleting multiple records.
  • Documentation

    • Expanded and clarified documentation for client API methods, options, and internal operations for better usability and understanding.
  • Tests

    • Added tests for the new updateManyAndReturn feature.
    • Added tests for deleteMany with the limit option.
    • Extended tests for relation counting with nested and filtered selections.
    • Improved type-checking tests for returned fields and counts.

@coderabbitai
Copy link

coderabbitai bot commented Jun 16, 2025

Walkthrough

This update introduces a new updateManyAndReturn method to the ORM client, enabling batch updates that return the updated entities. Type definitions and documentation for CRUD operations are significantly expanded and clarified, including enhanced relation count typing and method documentation. Additional dialect support flags and validation logic are added, and comprehensive tests are included for the new and updated features.

Changes

File(s) Change Summary
packages/runtime/src/client/client-impl.ts Added updateManyAndReturn method to model CRUD handler; updated JSDoc for client export.
packages/runtime/src/client/crud-types.ts Enhanced type definitions for batch updates/returns, relation counts, and CRUD interface; added extensive JSDoc for all methods.
packages/runtime/src/client/crud/operations/base.ts Added support for returning updated/deleted entities and explicit limit handling in batch operations; updated method signatures.
packages/runtime/src/client/crud/operations/update.ts Added updateManyAndReturn operation to handler; implemented logic for returning updated rows.
packages/runtime/src/client/crud/operations/delete.ts Updated calls to delete to explicitly pass limit argument.
packages/runtime/src/client/crud/validator.ts Added validation for updateManyAndReturn arguments; improved mutual exclusivity checks for select/omit.
packages/runtime/src/client/crud/dialects/base.ts Added JSDoc comments to abstract methods and properties for dialect capabilities.
packages/runtime/src/client/crud/dialects/postgresql.ts,
.../sqlite.ts
Added supportsDeleteWithLimit getter returning false for both dialects.
packages/runtime/src/client/contract.ts Marked $pushSchema() method as private via JSDoc.
packages/runtime/src/client/options.ts Added JSDoc comments to client options and properties.
TODO.md Added and checked off "JSDoc for CRUD methods" in the TODO list.
packages/runtime/test/client-api/update-many.test.ts Added test for updateManyAndReturn verifying returned updated entities.
packages/runtime/test/client-api/delete-many.test.ts Added test for deleteMany with limit option.
packages/runtime/test/client-api/find.test.ts Added tests for nested relation _count.select queries.
packages/runtime/test/client-api/create-many-and-return.test.ts Added TypeScript expectation comments for type errors on omitted fields.
packages/runtime/test/typing/verify-typing.ts Updated logging for more precise access to nested count properties.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant ModelHandler
    participant UpdateOperationHandler
    participant Database

    Client->>ModelHandler: updateManyAndReturn(args)
    ModelHandler->>UpdateOperationHandler: handle('updateManyAndReturn', args)
    UpdateOperationHandler->>Database: Begin transaction
    UpdateOperationHandler->>Database: Update records (with where/data)
    Database-->>UpdateOperationHandler: Updated row IDs
    UpdateOperationHandler->>Database: Select updated rows by IDs
    Database-->>UpdateOperationHandler: Updated entities
    UpdateOperationHandler->>ModelHandler: Return updated entities
    ModelHandler->>Client: Return updated entities
Loading

Poem

A rabbit hopped through fields of code,
Where batch updates now return their load.
With types refined and docs anew,
The client’s power only grew!
Tests all passed, the dialects know—
When limits matter, just say “no.”
🐇✨ Hooray for CRUD, both old and new!

✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • 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

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

🔭 Outside diff range comments (4)
packages/runtime/src/client/crud/operations/delete.ts (1)

58-64: 🛠️ Refactor suggestion

Missing validation: limit should be a positive integer

runDeleteMany forwards args?.limit unchecked. Add a guard in the input validator (or here) to ensure limit is a positive integer; negative or zero silently produces confusing results.

-        const result = await this.delete(
+        if (args?.limit !== undefined && args.limit <= 0) {
+            throw new Error('`limit` must be a positive integer');
+        }
+        const result = await this.delete(
             this.kysely,
             this.model,
             args?.where,
             args?.limit,
             false
         );
packages/runtime/src/client/crud/validator.ts (1)

1100-1119: ⚠️ Potential issue

Schema needs .optional() for consistency

makeUpdateManyAndReturnSchema returns a required object, but
validateUpdateManyAndReturnArgs allows undefined.
Calling updateManyAndReturn() with no args will currently throw.

-        const result = base.merge(
+        const result = base.merge(
             z.object({
                 select: this.makeSelectSchema(model).optional(),
                 omit: this.makeOmitSchema(model).optional(),
             })
         );
-        return this.refineForSelectOmitMutuallyExclusive(result);
+        return this.refineForSelectOmitMutuallyExclusive(result).optional();
packages/runtime/src/client/crud/operations/base.ts (2)

1471-1505: 🛠️ Refactor suggestion

Add basic validation for limit

limit is forwarded to SQL without checks. Negative or zero values will compile but behave unpredictably.

if (limit !== undefined && limit <= 0) {
    throw new InternalError('limit must be a positive integer');
}

A tiny guard avoids accidental “no-op” / undefined behaviour on some dialects.


1458-1467: 🛠️ Refactor suggestion

Silently dropping relation fields hides user errors

Relation attributes in data are ignored (continue path).
Fail fast to save debugging time:

if (isRelationField(...) ) {
    throw new QueryError('updateMany does not support relation updates');
}

Prefer an explicit error to surprising partial updates.

🧹 Nitpick comments (6)
TODO.md (1)

57-59: Indentation violates MD007

The new checklist item is indented with 8 spaces, while the rest of the list uses 4. This triggers markdown-lint (see static-analysis hint).

-        -   [x] JSDoc for CRUD methods
+    -   [x] JSDoc for CRUD methods
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

57-57: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


58-58: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)


59-59: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)

packages/runtime/test/client-api/create-many-and-return.test.ts (1)

83-85: Prefer runtime-only assertions over @ts-expect-error in tests

@ts-expect-error suppresses the compiler error but still emits JS that touches name, so we need the undefined assertions anyway.
Using Jest/Vitest you could avoid emitting the extra JS by asserting on shape instead:

-// @ts-expect-error
-expect(r[0]!.name).toBeUndefined();
+expect(r[0]).not.toHaveProperty('name');

Same for the second block. This keeps the type-safety (compiler will still complain if name appears) and removes dead code.

Also applies to: 91-93

packages/runtime/test/typing/verify-typing.ts (1)

77-79: Prefer compile-time assertions over runtime console.log in typing tests

The added console.log statements validate access to nested _count fields only at runtime. Consider using ts-expect-error / expectAssignable style assertions (e.g. expectTypeOf(user3._count.posts).toEqualTypeOf<number>()) so that the test continues to guard the type surface without producing noisy runtime output.

packages/runtime/src/client/crud/operations/delete.ts (1)

40-46: Explicit undefined arg for limit is redundant and obscures the call-site

runDelete always deletes at most one record (unique filter), so passing an extra positional undefined for limit provides no value and makes the signature harder to follow. Omitting the param entirely keeps the call in-sync with the logical need while still relying on the default undefined.

-        const result = await this.delete(
-            this.kysely,
-            this.model,
-            args.where,
-            undefined,
-            false
-        );
+        const result = await this.delete(
+            this.kysely,
+            this.model,
+            args.where,
+            /* limit */ undefined,
+            /* returnData */ false
+        );

Keeping the named comment is optional but clarifies intent without the extra parameter.

packages/runtime/test/client-api/update-many.test.ts (1)

101-118: Consider adding a “no-match” assertion

Nice happy-path test. You may also want a case where updateManyAndReturn finds zero rows and returns an empty array to lock in that behaviour.

packages/runtime/src/client/crud/operations/update.ts (1)

94-121: Minor optimisation opportunity

You already have the updated rows in updateResult; doing an extra
read round-trip just to apply select/omit incurs an extra query and
builds a potentially huge OR clause.
Consider post-processing updateResult in memory instead.

(Not blocking.)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9bf9479 and 7a67ebd.

📒 Files selected for processing (17)
  • TODO.md (1 hunks)
  • packages/runtime/src/client/client-impl.ts (2 hunks)
  • packages/runtime/src/client/contract.ts (1 hunks)
  • packages/runtime/src/client/crud-types.ts (5 hunks)
  • packages/runtime/src/client/crud/dialects/base.ts (1 hunks)
  • packages/runtime/src/client/crud/dialects/postgresql.ts (1 hunks)
  • packages/runtime/src/client/crud/dialects/sqlite.ts (1 hunks)
  • packages/runtime/src/client/crud/operations/base.ts (7 hunks)
  • packages/runtime/src/client/crud/operations/delete.ts (2 hunks)
  • packages/runtime/src/client/crud/operations/update.ts (4 hunks)
  • packages/runtime/src/client/crud/validator.ts (4 hunks)
  • packages/runtime/src/client/options.ts (2 hunks)
  • packages/runtime/test/client-api/create-many-and-return.test.ts (1 hunks)
  • packages/runtime/test/client-api/delete-many.test.ts (1 hunks)
  • packages/runtime/test/client-api/find.test.ts (1 hunks)
  • packages/runtime/test/client-api/update-many.test.ts (1 hunks)
  • packages/runtime/test/typing/verify-typing.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
packages/runtime/src/client/options.ts (1)
packages/sdk/src/schema/schema.ts (1)
  • SchemaDef (11-18)
packages/runtime/src/client/crud/validator.ts (2)
packages/sdk/src/schema/schema.ts (1)
  • GetModels (105-108)
packages/runtime/src/client/crud-types.ts (1)
  • UpdateManyAndReturnArgs (812-818)
packages/runtime/src/client/crud/operations/update.ts (3)
packages/runtime/src/client/crud-types.ts (1)
  • UpdateManyAndReturnArgs (812-818)
packages/sdk/src/schema/schema.ts (1)
  • GetModels (105-108)
packages/runtime/src/client/query-utils.ts (1)
  • getIdValues (183-196)
packages/runtime/src/client/crud/operations/base.ts (5)
packages/runtime/src/client/index.ts (1)
  • ToKysely (7-7)
packages/runtime/src/client/query-builder.ts (1)
  • ToKysely (18-18)
packages/sdk/src/schema/schema.ts (1)
  • GetModels (105-108)
packages/runtime/src/client/errors.ts (1)
  • InternalError (7-11)
packages/runtime/src/client/query-utils.ts (1)
  • getIdFields (40-46)
packages/runtime/src/client/crud-types.ts (1)
packages/sdk/src/schema/schema.ts (2)
  • SchemaDef (11-18)
  • GetModels (105-108)
🪛 markdownlint-cli2 (0.17.2)
TODO.md

58-58: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)

🪛 Biome (1.9.4)
packages/runtime/src/client/options.ts

[error] 73-73: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build-test (20.x)
🔇 Additional comments (10)
packages/runtime/src/client/contract.ts (1)

66-69: JSDoc visibility correctly clarified

The @private tag is the right way to hide $pushSchema() from public docs while keeping it available for tests. No further action needed.

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

325-327: Redundant override?

supportsDeleteWithLimit is hard-coded to false, which is correct for SQLite. If the base class already defaults to false, this override is unnecessary noise. Otherwise, keep it.

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

393-395: Same question about default implementation

As with the SQLite dialect, verify whether the base class default is already false. If so, consider removing this duplicate override to reduce maintenance overhead.

packages/runtime/src/client/client-impl.ts (1)

427-434: updateManyAndReturn wired correctly – ensure typings & docs are in lock-step

The new handler mirrors createManyAndReturn, using postProcess=true, which is appropriate because returned rows need transformation. 👍

Please double-check that:

  1. ModelOperations includes updateManyAndReturn (looks covered in crud-types.ts).
  2. InputValidator enforces mutually exclusive select / include / omit the same way as other batch-returning methods.
  3. Docs (JSDoc & README) mention the new capability.

Otherwise the addition LGTM.

packages/runtime/test/client-api/delete-many.test.ts (1)

58-80: Great coverage for limit, consider dialect skip logic

The test exercises both zero-match and partial-delete paths—nice!
One caveat: for dialects that don’t support DELETE … LIMIT, the client may emulate the behaviour in memory or fall back silently. Ensure the test matrix skips or adapts for those dialects, otherwise CI will fail once support for such dialects is re-enabled.

packages/runtime/test/client-api/find.test.ts (1)

829-850: Tests look good – covers both simple and filtered counts.

packages/runtime/src/client/crud/validator.ts (1)

767-774: *Good parity with other AndReturn schemas

Refactor removes include and adds mutual-exclusion refinement – looks correct.

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

1177-1211: Appreciate the added JSDoc – clarifies the dialect contract.

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

1483-1503: Duplicate buildIdFieldRefs computation

buildIdFieldRefs is invoked twice inside the same expression – once with a ts-expect-error.
Store the result in a local variable to avoid repetition and drop the suppress-comment.

[ suggest_optional_refactor ]

packages/runtime/src/client/crud-types.ts (1)

1696-1699: Use SelectSubset for updateManyAndReturn to keep API consistency

createManyAndReturn already leverages SelectSubset to ban illegal select+omit combos.
Switching here keeps the safeguard:

- updateManyAndReturn<T extends UpdateManyAndReturnArgs<...>>(
-     args: Subset<T, UpdateManyAndReturnArgs<...>>
+ updateManyAndReturn<T extends UpdateManyAndReturnArgs<...>>(
+     args: SelectSubset<T, UpdateManyAndReturnArgs<...>>

[ suggest_essential_refactor ]

@ymc9 ymc9 merged commit 53bf171 into dev Jun 16, 2025
5 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jun 28, 2025
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