Skip to content

feat: exists operation#550

Merged
ymc9 merged 10 commits intozenstackhq:devfrom
sanny-io:feat/exists-operation
Jan 7, 2026
Merged

feat: exists operation#550
ymc9 merged 10 commits intozenstackhq:devfrom
sanny-io:feat/exists-operation

Conversation

@sanny-io
Copy link
Contributor

@sanny-io sanny-io commented Dec 30, 2025

Adds an exists operation, which performs a SELECT EXISTS(SELECT 1 FROM ... WHERE ...) query and returns a boolean. I'm probably missing some things, including test coverage. Let me know what you would like to see done.

Prisma issues: prisma/prisma#5022 prisma/prisma#5046

Sample Usage

const exists = await db.user.exists({
    where: {
        id: 1,
    },
});

Summary by CodeRabbit

  • New Features

    • Added existence-check support: new exists() model API returning boolean, ExistsArgs type for filters, and useExists hooks for TanStack Query (React, Svelte, Vue).
    • RPC and client query plumbing updated to expose model existence checks.
  • Tests

    • Added typing checks, RPC/unit tests, and comprehensive end-to-end tests validating exists() and useExists with various where scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 30, 2025

📝 Walkthrough

Walkthrough

Adds an "exists" model query across the stack: new ExistsArgs type, ExistsOperationHandler and existsNonUnique, model-level exists() API, TanStack-Query useExists hooks (React/Vue/Svelte), RPC handling, and tests (typing, RPC, E2E).

Changes

Cohort / File(s) Summary
TanStack-Query clients
packages/clients/tanstack-query/src/react.ts, packages/clients/tanstack-query/src/vue.ts, packages/clients/tanstack-query/src/svelte/index.svelte.ts
Import ExistsArgs; add useExists signature to ModelQueryHooks; implement useExists to call useInternalQuery(..., 'exists', ...).
ORM public API / types
packages/orm/src/client/crud-types.ts, packages/orm/src/client/contract.ts
Export new ExistsArgs type alias and add exists(...) method signature to the model operations contract.
ORM implementation - client & operations
packages/orm/src/client/client-impl.ts, packages/orm/src/client/crud/operations/base.ts, packages/orm/src/client/crud/operations/exists.ts
Expose model exists() in client impl; add 'exists' to operation unions; implement existsNonUnique helper and ExistsOperationHandler to validate and execute existence queries.
ORM validation
packages/orm/src/client/crud/validator/index.ts
Add validateExistsArgs and makeExistsSchema to validate exists args (optional where).
Type generation & test schema types
packages/sdk/src/ts-schema-generator.ts, packages/clients/tanstack-query/test/schemas/basic/input.ts
Include ExistsArgs in generated imports/exports and add model-specific *ExistsArgs type aliases used by tests.
RPC server
packages/server/src/api/rpc/index.ts
Add 'exists' case to RPC operation handling; treat as a GET/read route.
Tests
packages/clients/tanstack-query/test/react-typing-test.ts, packages/clients/tanstack-query/test/vue-typing-test.ts, packages/clients/tanstack-query/test/svelte-typing-test.ts, packages/server/test/api/rpc.test.ts, tests/e2e/orm/client-api/exists.test.ts
Add typing checks for useExists across frameworks, RPC tests for /model/exists, and E2E tests validating exists() for various filters and nested relations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐇 I hopped the query fields with glee,

Nose to the where, I checked for thee.
A boolean whisper — true or not;
I sniffed the rows and found the spot.
Exists! I twitched and danced a lot. ✨

🚥 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 'feat: exists operation' is clear, concise, and accurately describes the primary change - the addition of a new exists query operation across the codebase.

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

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 06509cf and 9ff7e5f.

📒 Files selected for processing (1)
  • packages/orm/src/client/crud/operations/base.ts
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Implement plugin hooks at ORM, Kysely, and entity mutation levels for query interception and customization
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Implement plugin hooks at ORM, Kysely, and entity mutation levels for query interception and customization

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Use Kysely as the query builder interface for low-level database queries, avoiding raw SQL when possible

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-12-30T15:07:06.254Z
Learnt from: mwillbanks
Repo: zenstackhq/zenstack-v3 PR: 550
File: packages/orm/src/client/crud/operations/base.ts:158-159
Timestamp: 2025-12-30T15:07:06.254Z
Learning: Do not use ts-expect-error in production code within the zenstackhq/zenstack-v3 repo (e.g., packages/*). Use explicit type annotations, targeted type assertions, or refactor to resolve the type error. ts-expect-error may be acceptable only in test files for stubbing or temporary silencing. Ensure production code is type-safe and maintainable.

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/**/type*.{ts,tsx} : Ensure TypeScript inference and type coverage are validated through type coverage tests

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy tests

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to **/*.zmodel : ZModel schema files should define database structure and policies that compile to TypeScript via `zenstack generate`

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/cli/**/*.test.{ts,tsx} : CLI package tests should focus on action-specific tests for each command

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
🧬 Code graph analysis (1)
packages/orm/src/client/crud/operations/base.ts (5)
packages/orm/src/client/executor/zenstack-query-executor.ts (1)
  • kysely (77-79)
packages/plugins/policy/src/policy-handler.ts (1)
  • kysely (76-78)
packages/orm/src/client/index.ts (1)
  • ToKysely (10-10)
packages/schema/src/schema.ts (1)
  • GetModels (121-121)
packages/orm/src/client/errors.ts (1)
  • createDBQueryError (122-129)
⏰ 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 (22.x, postgresql)
  • GitHub Check: build-test (22.x, sqlite)
🔇 Additional comments (2)
packages/orm/src/client/crud/operations/base.ts (2)

72-73: LGTM!

The 'exists' operation is properly added to the CoreCrudOperation union type, enabling the new exists functionality throughout the CRUD operation flow.


150-174: LGTM!

The existsNonUnique method is well-implemented with proper cross-database compatibility. The use of !!result[0]?.exists correctly handles both integer (MySQL/SQLite) and boolean (PostgreSQL) return values from the EXISTS query. Error handling is comprehensive, and the query construction follows the established Kysely-based patterns used throughout the codebase.


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

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
packages/server/test/api/rpc.test.ts (1)

30-37: Good RPC coverage for exists before/after creation

The new checks around /user/exists validate both the false-then-true flow and status code, matching how other read endpoints are tested. If you want to extend coverage later, you could optionally add a small test for invalid methods (e.g. POST /user/exists) to lock in the GET-only contract, but the current additions are already solid.

Also applies to: 69-76

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

30-31: Wire exists without result post‑processing

The exists operation is correctly routed through createPromise and ExistsOperationHandler, so it participates in the same plugin/onQuery and transaction flow as other operations (which is good). However, passing postProcess = true here means ResultProcessor may be invoked for a boolean, which is unnecessary and slightly confusing for an operation that never uses select/include/omit.

Consider aligning it with count/aggregate by disabling post-processing:

Suggested change
-        exists: (args: unknown) => {
-            return createPromise(
-                'exists',
-                'exists',
-                args,
-                new ExistsOperationHandler<any>(client, model, inputValidator),
-                true,
-            );
-        },
+        exists: (args: unknown) => {
+            return createPromise(
+                'exists',
+                'exists',
+                args,
+                new ExistsOperationHandler<any>(client, model, inputValidator),
+                /* postProcess */ false,
+            );
+        },

Also applies to: 603-611

packages/orm/src/client/contract.ts (1)

15-42: ORM contract for exists matches the rest of the surface

Importing ExistsArgs and adding the exists method with the T extends ExistsArgs + Subset<..., ExistsArgs> pattern keeps typing consistent with other operations and returns a simple boolean as expected. You may optionally add a short JSDoc block and example (like the other methods) so this shows up clearly in generated docs, but the type-level contract itself looks solid.

Also applies to: 833-835

tests/e2e/orm/client-api/exists.test.ts (1)

17-51: Consider consolidating redundant test cases.

The three tests "works with no args", "works with empty args", and "works with empty where" all verify the same behavior: checking existence without any filtering. While it's valuable to test different argument formats (exists(), exists({}), exists({ where: {} })), these could be consolidated into a single test with multiple assertions to reduce duplication and improve test maintainability.

💡 Suggested consolidation
-    it('works with no args', async () => {
+    it('works with various empty argument formats', async () => {
         await expect(client.user.exists()).resolves.toBe(false);
+        await expect(client.user.exists({})).resolves.toBe(false);
+        await expect(client.user.exists({ where: {} })).resolves.toBe(false);
 
         await client.user.create({
             data: {
                 email: 'test@email.com',
             },
         });
 
         await expect(client.user.exists()).resolves.toBe(true);
-    });
-
-    it('works with empty args', async () => {
-        await expect(client.user.exists({})).resolves.toBe(false);
-
-        await client.user.create({
-            data: {
-                email: 'test@email.com',
-            },
-        });
-
         await expect(client.user.exists({})).resolves.toBe(true);
-    });
-
-    it('works with empty where', async () => {
-        await expect(client.user.exists({ where: {} })).resolves.toBe(false);
-
-        await client.user.create({
-            data: {
-                email: 'test@email.com',
-            },
-        });
-
         await expect(client.user.exists({ where: {} })).resolves.toBe(true);
     });
packages/clients/tanstack-query/src/react.ts (1)

169-172: Consider adding a suspense variant for consistency.

All other query operations in the React client have corresponding suspense variants (useSuspenseFindUnique, useSuspenseFindFirst, useSuspenseFindMany, useSuspenseCount, useSuspenseAggregate, useSuspenseGroupBy), but useExists does not have a useSuspenseExists counterpart. For consistency and to support React Suspense patterns, consider adding:

useSuspenseExists<T extends ExistsArgs<Schema, Model>>(
    args?: Subset<T, ExistsArgs<Schema, Model>>,
    options?: ModelSuspenseQueryOptions<boolean>,
): ModelSuspenseQueryResult<boolean>;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65388a5 and d4d6d9d.

📒 Files selected for processing (17)
  • packages/clients/tanstack-query/src/react.ts
  • packages/clients/tanstack-query/src/svelte/index.svelte.ts
  • packages/clients/tanstack-query/src/vue.ts
  • packages/clients/tanstack-query/test/react-typing-test.ts
  • packages/clients/tanstack-query/test/schemas/basic/input.ts
  • packages/clients/tanstack-query/test/svelte-typing-test.ts
  • packages/clients/tanstack-query/test/vue-typing-test.ts
  • packages/orm/src/client/client-impl.ts
  • packages/orm/src/client/contract.ts
  • packages/orm/src/client/crud-types.ts
  • packages/orm/src/client/crud/operations/base.ts
  • packages/orm/src/client/crud/operations/exists.ts
  • packages/orm/src/client/crud/validator/index.ts
  • packages/sdk/src/ts-schema-generator.ts
  • packages/server/src/api/rpc/index.ts
  • packages/server/test/api/rpc.test.ts
  • tests/e2e/orm/client-api/exists.test.ts
🧰 Additional context used
📓 Path-based instructions (1)
tests/e2e/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

E2E tests should validate real-world schema compatibility with established projects

Files:

  • tests/e2e/orm/client-api/exists.test.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Implement plugin hooks at ORM, Kysely, and entity mutation levels for query interception and customization
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Use Kysely as the query builder interface for low-level database queries, avoiding raw SQL when possible
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy tests
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy tests

Applied to files:

  • packages/clients/tanstack-query/test/svelte-typing-test.ts
  • packages/orm/src/client/client-impl.ts
  • packages/clients/tanstack-query/test/vue-typing-test.ts
  • packages/orm/src/client/contract.ts
  • packages/clients/tanstack-query/test/react-typing-test.ts
  • packages/orm/src/client/crud/validator/index.ts
  • tests/e2e/orm/client-api/exists.test.ts
  • packages/clients/tanstack-query/test/schemas/basic/input.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/**/type*.{ts,tsx} : Ensure TypeScript inference and type coverage are validated through type coverage tests

Applied to files:

  • packages/clients/tanstack-query/test/svelte-typing-test.ts
  • packages/clients/tanstack-query/test/vue-typing-test.ts
  • packages/clients/tanstack-query/test/react-typing-test.ts
  • tests/e2e/orm/client-api/exists.test.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Implement plugin hooks at ORM, Kysely, and entity mutation levels for query interception and customization

Applied to files:

  • packages/clients/tanstack-query/test/svelte-typing-test.ts
  • packages/orm/src/client/client-impl.ts
  • packages/orm/src/client/contract.ts
  • packages/clients/tanstack-query/src/svelte/index.svelte.ts
  • packages/clients/tanstack-query/test/react-typing-test.ts
  • packages/orm/src/client/crud/validator/index.ts
  • packages/clients/tanstack-query/src/vue.ts
  • packages/clients/tanstack-query/src/react.ts
  • packages/orm/src/client/crud/operations/base.ts
  • tests/e2e/orm/client-api/exists.test.ts
  • packages/orm/src/client/crud-types.ts
  • packages/clients/tanstack-query/test/schemas/basic/input.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects

Applied to files:

  • packages/clients/tanstack-query/test/svelte-typing-test.ts
  • tests/e2e/orm/client-api/exists.test.ts
  • packages/clients/tanstack-query/test/schemas/basic/input.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/cli/**/*.test.{ts,tsx} : CLI package tests should focus on action-specific tests for each command

Applied to files:

  • packages/clients/tanstack-query/test/svelte-typing-test.ts
  • tests/e2e/orm/client-api/exists.test.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Use Kysely as the query builder interface for low-level database queries, avoiding raw SQL when possible

Applied to files:

  • packages/orm/src/client/contract.ts
  • packages/clients/tanstack-query/src/svelte/index.svelte.ts
  • packages/clients/tanstack-query/test/react-typing-test.ts
  • packages/clients/tanstack-query/src/vue.ts
  • packages/clients/tanstack-query/src/react.ts
  • packages/orm/src/client/crud/operations/base.ts
  • packages/orm/src/client/crud-types.ts
  • packages/clients/tanstack-query/test/schemas/basic/input.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to **/*.zmodel : ZModel schema files should define database structure and policies that compile to TypeScript via `zenstack generate`

Applied to files:

  • packages/orm/src/client/crud/validator/index.ts
🧬 Code graph analysis (9)
packages/orm/src/client/client-impl.ts (1)
packages/orm/src/client/crud/operations/exists.ts (1)
  • ExistsOperationHandler (4-12)
packages/orm/src/client/contract.ts (2)
packages/orm/src/client/crud-types.ts (2)
  • ExistsArgs (1082-1082)
  • Subset (896-898)
packages/orm/src/client/promise.ts (1)
  • ZenStackPromise (7-13)
packages/clients/tanstack-query/src/svelte/index.svelte.ts (1)
packages/orm/src/client/crud-types.ts (2)
  • ExistsArgs (1082-1082)
  • Subset (896-898)
packages/server/test/api/rpc.test.ts (1)
packages/server/src/api/rpc/index.ts (1)
  • handleRequest (40-165)
packages/orm/src/client/crud/validator/index.ts (2)
packages/schema/src/schema.ts (1)
  • GetModels (121-121)
packages/orm/src/client/crud-types.ts (1)
  • ExistsArgs (1082-1082)
packages/clients/tanstack-query/src/vue.ts (2)
packages/orm/src/client/crud-types.ts (2)
  • ExistsArgs (1082-1082)
  • Subset (896-898)
packages/clients/tanstack-query/src/react.ts (1)
  • useInternalQuery (405-426)
packages/orm/src/client/crud/operations/base.ts (4)
packages/orm/src/client/executor/zenstack-query-executor.ts (1)
  • kysely (77-79)
packages/orm/src/client/index.ts (1)
  • ToKysely (10-10)
packages/schema/src/schema.ts (1)
  • GetModels (121-121)
packages/orm/src/client/errors.ts (1)
  • createDBQueryError (122-129)
tests/e2e/orm/client-api/exists.test.ts (2)
packages/orm/src/client/contract.ts (1)
  • ClientContract (64-198)
packages/testtools/src/client.ts (1)
  • createTestClient (101-248)
packages/orm/src/client/crud-types.ts (1)
packages/schema/src/schema.ts (2)
  • SchemaDef (11-19)
  • GetModels (121-121)
⏰ 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 (22.x, postgresql)
  • GitHub Check: build-test (22.x, sqlite)
🔇 Additional comments (6)
packages/clients/tanstack-query/test/svelte-typing-test.ts (1)

21-23: Typing coverage for useExists looks consistent with other hooks

The new useExists checks mirror the existing useFindFirst/useFindMany patterns and validate both no-arg and where variants. This is sufficient typing coverage for the Svelte client.

packages/clients/tanstack-query/test/vue-typing-test.ts (1)

21-23: Vue useExists typings wired correctly

The added checks for client.user.useExists() and useExists({ where }) align with existing Vue query hooks and confirm that data.value is a boolean-typed ref. No further typing assertions seem necessary here.

packages/server/src/api/rpc/index.ts (1)

70-87: RPC handler correctly exposes exists as a read operation

Adding case 'exists' into the existing GET-only branch reuses the same query unmarshalling and validation flow as other read operations, which is exactly what you want for a boolean existence check. No additional special cases are needed at this layer.

packages/sdk/src/ts-schema-generator.ts (1)

1537-1559: Generated input schema now correctly exposes *ExistsArgs

Including ExistsArgs in inputTypes ensures input.ts exports ModelExistsArgs aliases, keeping generated schemas aligned with the new ORM exists API and the tanstack-query typings that depend on these aliases.

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

1033-1038: ExistsArgs alias is minimal and well‑scoped

Defining ExistsArgs as FilterArgs<Schema, Model> keeps the exists API focused on where filters only, while still supporting the full WhereInput expressiveness (relations, $expr, etc.). This matches the intended semantics of an existence check.

Also applies to: 1081-1083

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

71-72: LGTM!

The exists operation is correctly added to the CoreCrudOperation union type.

@sanny-io
Copy link
Contributor Author

I wonder how this should be handled with field omission. Should omitted fields be ignored? Most interesting...

@mwillbanks
Copy link
Contributor

I wonder how this should be handled with field omission. Should omitted fields be ignored? Most interesting...

I would think that omitted fields would be ignored since you're purely doing an existence check and that omitted fields are purely on the return side and not input side, I think ignoring that is safe.

Copy link
Contributor

@mwillbanks mwillbanks left a comment

Choose a reason for hiding this comment

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

Excellent addition, I would certainly utilize this from time to time... Normally I end up just utilizing FindFirst but exists would certainly be helpful in cases where I don't need to know what the contents are.

Copy link
Member

@ymc9 ymc9 left a comment

Choose a reason for hiding this comment

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

Hi @sanny-io , sorry for the late review. This is an awesome addition and very well-implemented code. Thanks for working on it!

Please find my comments attached. We can include it in the upcoming 3.2.0 release.

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 (1)
packages/server/test/api/rpc.test.ts (1)

69-76: LGTM! Good baseline test for existing record.

The test correctly verifies that exists returns true after the user is created.

Optional: Consider additional test scenarios

For more comprehensive coverage of the exists operation, you might consider adding tests for:

  • exists with empty/no where clause
  • exists with complex where conditions (AND/OR/NOT)
  • exists with relation filters
  • exists with invalid model names (error handling)

However, these are optional enhancements that can be addressed in follow-up work.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6f3afa and 1391c92.

📒 Files selected for processing (3)
  • packages/orm/src/client/crud/operations/base.ts
  • packages/server/src/api/rpc/index.ts
  • packages/server/test/api/rpc.test.ts
🧰 Additional context used
🧠 Learnings (8)
📚 Learning: 2025-12-30T15:07:06.254Z
Learnt from: mwillbanks
Repo: zenstackhq/zenstack-v3 PR: 550
File: packages/orm/src/client/crud/operations/base.ts:158-159
Timestamp: 2025-12-30T15:07:06.254Z
Learning: Do not use ts-expect-error in production code within the zenstackhq/zenstack-v3 repo (e.g., packages/*). Use explicit type annotations, targeted type assertions, or refactor to resolve the type error. ts-expect-error may be acceptable only in test files for stubbing or temporary silencing. Ensure production code is type-safe and maintainable.

Applied to files:

  • packages/server/src/api/rpc/index.ts
  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.test.{ts,tsx} : ORM package tests should include comprehensive client API tests and policy tests

Applied to files:

  • packages/server/test/api/rpc.test.ts
  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Use Kysely as the query builder interface for low-level database queries, avoiding raw SQL when possible

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/orm/**/*.{ts,tsx} : Implement plugin hooks at ORM, Kysely, and entity mutation levels for query interception and customization

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/**/type*.{ts,tsx} : Ensure TypeScript inference and type coverage are validated through type coverage tests

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to tests/e2e/**/*.{ts,tsx} : E2E tests should validate real-world schema compatibility with established projects

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to **/*.zmodel : ZModel schema files should define database structure and policies that compile to TypeScript via `zenstack generate`

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
📚 Learning: 2025-11-26T01:55:04.540Z
Learnt from: CR
Repo: zenstackhq/zenstack-v3 PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T01:55:04.540Z
Learning: Applies to packages/zenstackhq/cli/**/*.test.{ts,tsx} : CLI package tests should focus on action-specific tests for each command

Applied to files:

  • packages/orm/src/client/crud/operations/base.ts
🧬 Code graph analysis (2)
packages/server/test/api/rpc.test.ts (1)
packages/server/src/api/rpc/index.ts (1)
  • handleRequest (40-165)
packages/orm/src/client/crud/operations/base.ts (5)
packages/orm/src/client/plugin.ts (1)
  • CoreCrudOperation (57-57)
packages/orm/src/client/executor/zenstack-query-executor.ts (1)
  • kysely (77-79)
packages/orm/src/client/index.ts (1)
  • ToKysely (10-10)
packages/schema/src/schema.ts (1)
  • GetModels (121-121)
packages/orm/src/client/errors.ts (1)
  • createDBQueryError (122-129)
⏰ 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 (22.x, sqlite)
  • GitHub Check: build-test (22.x, postgresql)
🔇 Additional comments (4)
packages/server/src/api/rpc/index.ts (1)

76-76: LGTM! Consistent with other read operations.

The exists operation is correctly added alongside other read operations, using GET method and the same query parameter parsing logic.

packages/server/test/api/rpc.test.ts (1)

30-37: LGTM! Good baseline test for non-existent record.

The test correctly verifies that exists returns false for a non-existent user.

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

57-73: LGTM! Clean addition of the 'exists' operation type.

The exists operation is correctly added to the CoreCrudOperation union type, following the established pattern.


75-75: LGTM! Type definition correctly includes the new operation.

The AllCrudOperation type automatically includes the new exists operation from CoreCrudOperation.

@sanny-io sanny-io requested a review from ymc9 January 7, 2026 10:03
Copy link
Member

@ymc9 ymc9 left a comment

Choose a reason for hiding this comment

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

LGTM!

@ymc9 ymc9 merged commit 446a483 into zenstackhq:dev Jan 7, 2026
5 of 6 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jan 8, 2026
@claude claude bot mentioned this pull request Jan 8, 2026
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