Conversation
📝 WalkthroughWalkthroughAdds an "exists" model query across the stack: new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🧠 Learnings (9)📓 Common learnings📚 Learning: 2025-11-26T01:55:04.540ZApplied to files:
📚 Learning: 2025-11-26T01:55:04.540ZApplied to files:
📚 Learning: 2025-12-30T15:07:06.254ZApplied to files:
📚 Learning: 2025-11-26T01:55:04.540ZApplied to files:
📚 Learning: 2025-11-26T01:55:04.540ZApplied to files:
📚 Learning: 2025-11-26T01:55:04.540ZApplied to files:
📚 Learning: 2025-11-26T01:55:04.540ZApplied to files:
📚 Learning: 2025-11-26T01:55:04.540ZApplied to files:
🧬 Code graph analysis (1)packages/orm/src/client/crud/operations/base.ts (5)
⏰ 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)
🔇 Additional comments (2)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
packages/server/test/api/rpc.test.ts (1)
30-37: Good RPC coverage forexistsbefore/after creationThe new checks around
/user/existsvalidate 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: Wireexistswithout result post‑processingThe
existsoperation is correctly routed throughcreatePromiseandExistsOperationHandler, so it participates in the same plugin/onQuery and transaction flow as other operations (which is good). However, passingpostProcess = truehere meansResultProcessormay 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 forexistsmatches the rest of the surfaceImporting
ExistsArgsand adding theexistsmethod with theT extends ExistsArgs+Subset<..., ExistsArgs>pattern keeps typing consistent with other operations and returns a simplebooleanas 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), butuseExistsdoes not have auseSuspenseExistscounterpart. 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
📒 Files selected for processing (17)
packages/clients/tanstack-query/src/react.tspackages/clients/tanstack-query/src/svelte/index.svelte.tspackages/clients/tanstack-query/src/vue.tspackages/clients/tanstack-query/test/react-typing-test.tspackages/clients/tanstack-query/test/schemas/basic/input.tspackages/clients/tanstack-query/test/svelte-typing-test.tspackages/clients/tanstack-query/test/vue-typing-test.tspackages/orm/src/client/client-impl.tspackages/orm/src/client/contract.tspackages/orm/src/client/crud-types.tspackages/orm/src/client/crud/operations/base.tspackages/orm/src/client/crud/operations/exists.tspackages/orm/src/client/crud/validator/index.tspackages/sdk/src/ts-schema-generator.tspackages/server/src/api/rpc/index.tspackages/server/test/api/rpc.test.tstests/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.tspackages/orm/src/client/client-impl.tspackages/clients/tanstack-query/test/vue-typing-test.tspackages/orm/src/client/contract.tspackages/clients/tanstack-query/test/react-typing-test.tspackages/orm/src/client/crud/validator/index.tstests/e2e/orm/client-api/exists.test.tspackages/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.tspackages/clients/tanstack-query/test/vue-typing-test.tspackages/clients/tanstack-query/test/react-typing-test.tstests/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.tspackages/orm/src/client/client-impl.tspackages/orm/src/client/contract.tspackages/clients/tanstack-query/src/svelte/index.svelte.tspackages/clients/tanstack-query/test/react-typing-test.tspackages/orm/src/client/crud/validator/index.tspackages/clients/tanstack-query/src/vue.tspackages/clients/tanstack-query/src/react.tspackages/orm/src/client/crud/operations/base.tstests/e2e/orm/client-api/exists.test.tspackages/orm/src/client/crud-types.tspackages/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.tstests/e2e/orm/client-api/exists.test.tspackages/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.tstests/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.tspackages/clients/tanstack-query/src/svelte/index.svelte.tspackages/clients/tanstack-query/test/react-typing-test.tspackages/clients/tanstack-query/src/vue.tspackages/clients/tanstack-query/src/react.tspackages/orm/src/client/crud/operations/base.tspackages/orm/src/client/crud-types.tspackages/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 foruseExistslooks consistent with other hooksThe new
useExistschecks mirror the existinguseFindFirst/useFindManypatterns and validate both no-arg andwherevariants. This is sufficient typing coverage for the Svelte client.packages/clients/tanstack-query/test/vue-typing-test.ts (1)
21-23: VueuseExiststypings wired correctlyThe added checks for
client.user.useExists()anduseExists({ where })align with existing Vue query hooks and confirm thatdata.valueis a boolean-typed ref. No further typing assertions seem necessary here.packages/server/src/api/rpc/index.ts (1)
70-87: RPC handler correctly exposesexistsas a read operationAdding
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*ExistsArgsIncluding
ExistsArgsininputTypesensuresinput.tsexportsModelExistsArgsaliases, 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:ExistsArgsalias is minimal and well‑scopedDefining
ExistsArgsasFilterArgs<Schema, Model>keeps the exists API focused onwherefilters only, while still supporting the fullWhereInputexpressiveness (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
existsoperation is correctly added to theCoreCrudOperationunion type.
|
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. |
mwillbanks
left a comment
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
existsreturnstrueafter the user is created.Optional: Consider additional test scenarios
For more comprehensive coverage of the
existsoperation, you might consider adding tests for:
existswith empty/no where clauseexistswith complex where conditions (AND/OR/NOT)existswith relation filtersexistswith 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
📒 Files selected for processing (3)
packages/orm/src/client/crud/operations/base.tspackages/server/src/api/rpc/index.tspackages/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.tspackages/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.tspackages/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
existsoperation 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
existsreturnsfalsefor a non-existent user.packages/orm/src/client/crud/operations/base.ts (2)
57-73: LGTM! Clean addition of the 'exists' operation type.The
existsoperation is correctly added to theCoreCrudOperationunion type, following the established pattern.
75-75: LGTM! Type definition correctly includes the new operation.The
AllCrudOperationtype automatically includes the newexistsoperation fromCoreCrudOperation.
Adds an
existsoperation, which performs aSELECT 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
Summary by CodeRabbit
New Features
Tests
✏️ Tip: You can customize this high-level summary in your review settings.