Skip to content
This repository was archived by the owner on Mar 1, 2026. It is now read-only.

Commit 446a483

Browse files
authored
feat: exists operation (#550)
* feat: exists operation * Add RPC handling. * Add frontend handling. * Add tests. * Fix postgres error. * Add JSDoc. * Remove `@ts-expect-error` * Disable post-processing. * Put semicolon back.
1 parent 27476ce commit 446a483

File tree

17 files changed

+340
-2
lines changed

17 files changed

+340
-2
lines changed

packages/clients/tanstack-query/src/react.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import type {
3333
CreateManyArgs,
3434
DeleteArgs,
3535
DeleteManyArgs,
36+
ExistsArgs,
3637
FindFirstArgs,
3738
FindManyArgs,
3839
FindUniqueArgs,
@@ -165,6 +166,11 @@ export type ModelQueryHooks<
165166
options?: ModelSuspenseQueryOptions<SimplifiedPlainResult<Schema, Model, T, Options> | null>,
166167
): ModelSuspenseQueryResult<SimplifiedPlainResult<Schema, Model, T, Options> | null>;
167168

169+
useExists<T extends ExistsArgs<Schema, Model>>(
170+
args?: Subset<T, ExistsArgs<Schema, Model>>,
171+
options?: ModelQueryOptions<boolean>,
172+
): ModelQueryResult<boolean>;
173+
168174
useFindMany<T extends FindManyArgs<Schema, Model>>(
169175
args?: SelectSubset<T, FindManyArgs<Schema, Model>>,
170176
options?: ModelQueryOptions<SimplifiedPlainResult<Schema, Model, T, Options>[]>,
@@ -308,6 +314,10 @@ export function useModelQueries<
308314
return useInternalSuspenseQuery(schema, modelName, 'findFirst', args, { ...rootOptions, ...options });
309315
},
310316

317+
useExists: (args: any, options?: any) => {
318+
return useInternalQuery(schema, modelName, 'exists', args, { ...rootOptions, ...options });
319+
},
320+
311321
useFindMany: (args: any, options?: any) => {
312322
return useInternalQuery(schema, modelName, 'findMany', args, { ...rootOptions, ...options });
313323
},

packages/clients/tanstack-query/src/svelte/index.svelte.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import type {
3434
CreateManyArgs,
3535
DeleteArgs,
3636
DeleteManyArgs,
37+
ExistsArgs,
3738
FindFirstArgs,
3839
FindManyArgs,
3940
FindUniqueArgs,
@@ -144,6 +145,11 @@ export type ModelQueryHooks<
144145
options?: Accessor<ModelQueryOptions<SimplifiedPlainResult<Schema, Model, T, Options> | null>>,
145146
): ModelQueryResult<SimplifiedPlainResult<Schema, Model, T, Options> | null>;
146147

148+
useExists<T extends ExistsArgs<Schema, Model>>(
149+
args?: Accessor<Subset<T, ExistsArgs<Schema, Model>>>,
150+
options?: Accessor<ModelQueryOptions<boolean>>,
151+
): ModelQueryResult<boolean>;
152+
147153
useFindMany<T extends FindManyArgs<Schema, Model>>(
148154
args?: Accessor<SelectSubset<T, FindManyArgs<Schema, Model>>>,
149155
options?: Accessor<ModelQueryOptions<SimplifiedPlainResult<Schema, Model, T, Options>[]>>,
@@ -257,6 +263,10 @@ export function useModelQueries<
257263
return useInternalQuery(schema, modelName, 'findFirst', args, merge(rootOptions, options));
258264
},
259265

266+
useExists: (args: any, options?: any) => {
267+
return useInternalQuery(schema, modelName, 'exists', args, merge(rootOptions, options));
268+
},
269+
260270
useFindMany: (args: any, options?: any) => {
261271
return useInternalQuery(schema, modelName, 'findMany', args, merge(rootOptions, options));
262272
},

packages/clients/tanstack-query/src/vue.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import type {
3232
CreateManyArgs,
3333
DeleteArgs,
3434
DeleteManyArgs,
35+
ExistsArgs,
3536
FindFirstArgs,
3637
FindManyArgs,
3738
FindUniqueArgs,
@@ -145,6 +146,11 @@ export type ModelQueryHooks<
145146
options?: MaybeRefOrGetter<ModelQueryOptions<SimplifiedPlainResult<Schema, Model, T, Options> | null>>,
146147
): ModelQueryResult<SimplifiedPlainResult<Schema, Model, T, Options> | null>;
147148

149+
useExists<T extends ExistsArgs<Schema, Model>>(
150+
args?: MaybeRefOrGetter<Subset<T, ExistsArgs<Schema, Model>>>,
151+
options?: MaybeRefOrGetter<ModelQueryOptions<boolean>>,
152+
): ModelQueryResult<boolean>;
153+
148154
useFindMany<T extends FindManyArgs<Schema, Model>>(
149155
args?: MaybeRefOrGetter<SelectSubset<T, FindManyArgs<Schema, Model>>>,
150156
options?: MaybeRefOrGetter<ModelQueryOptions<SimplifiedPlainResult<Schema, Model, T, Options>[]>>,
@@ -258,6 +264,10 @@ export function useModelQueries<
258264
return useInternalQuery(schema, modelName, 'findFirst', args, merge(rootOptions, options));
259265
},
260266

267+
useExists: (args: any, options?: any) => {
268+
return useInternalQuery(schema, modelName, 'exists', args, merge(rootOptions, options));
269+
},
270+
261271
useFindMany: (args: any, options?: any) => {
262272
return useInternalQuery(schema, modelName, 'findMany', args, merge(rootOptions, options));
263273
},

packages/clients/tanstack-query/test/react-typing-test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ check(client.user.useFindUnique({ where: { id: '1' }, include: { posts: true } }
1818
check(client.user.useFindFirst().data?.email);
1919
check(client.user.useFindFirst().data?.$optimistic);
2020

21+
check(client.user.useExists().data);
22+
check(client.user.useExists({ where: { id: '1' } }).data);
23+
2124
check(client.user.useFindMany().data?.[0]?.email);
2225
check(client.user.useFindMany().data?.[0]?.$optimistic);
2326

packages/clients/tanstack-query/test/schemas/basic/input.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
/* eslint-disable */
77

88
import { type SchemaType as $Schema } from "./schema-lite";
9-
import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput, QueryOptions as $QueryOptions } from "@zenstackhq/orm";
9+
import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, ExistsArgs as $ExistsArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput, QueryOptions as $QueryOptions } from "@zenstackhq/orm";
1010
import type { SimplifiedPlainResult as $Result, SelectIncludeOmit as $SelectIncludeOmit } from "@zenstackhq/orm";
1111
export type UserFindManyArgs = $FindManyArgs<$Schema, "User">;
1212
export type UserFindUniqueArgs = $FindUniqueArgs<$Schema, "User">;
1313
export type UserFindFirstArgs = $FindFirstArgs<$Schema, "User">;
14+
export type UserExistsArgs = $ExistsArgs<$Schema, "User">;
1415
export type UserCreateArgs = $CreateArgs<$Schema, "User">;
1516
export type UserCreateManyArgs = $CreateManyArgs<$Schema, "User">;
1617
export type UserCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "User">;
@@ -31,6 +32,7 @@ export type UserGetPayload<Args extends $SelectIncludeOmit<$Schema, "User", true
3132
export type PostFindManyArgs = $FindManyArgs<$Schema, "Post">;
3233
export type PostFindUniqueArgs = $FindUniqueArgs<$Schema, "Post">;
3334
export type PostFindFirstArgs = $FindFirstArgs<$Schema, "Post">;
35+
export type PostExistsArgs = $ExistsArgs<$Schema, "Post">;
3436
export type PostCreateArgs = $CreateArgs<$Schema, "Post">;
3537
export type PostCreateManyArgs = $CreateManyArgs<$Schema, "Post">;
3638
export type PostCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Post">;
@@ -51,6 +53,7 @@ export type PostGetPayload<Args extends $SelectIncludeOmit<$Schema, "Post", true
5153
export type CategoryFindManyArgs = $FindManyArgs<$Schema, "Category">;
5254
export type CategoryFindUniqueArgs = $FindUniqueArgs<$Schema, "Category">;
5355
export type CategoryFindFirstArgs = $FindFirstArgs<$Schema, "Category">;
56+
export type CategoryExistsArgs = $ExistsArgs<$Schema, "Category">;
5457
export type CategoryCreateArgs = $CreateArgs<$Schema, "Category">;
5558
export type CategoryCreateManyArgs = $CreateManyArgs<$Schema, "Category">;
5659
export type CategoryCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Category">;
@@ -71,6 +74,7 @@ export type CategoryGetPayload<Args extends $SelectIncludeOmit<$Schema, "Categor
7174
export type FooFindManyArgs = $FindManyArgs<$Schema, "Foo">;
7275
export type FooFindUniqueArgs = $FindUniqueArgs<$Schema, "Foo">;
7376
export type FooFindFirstArgs = $FindFirstArgs<$Schema, "Foo">;
77+
export type FooExistsArgs = $ExistsArgs<$Schema, "Foo">;
7478
export type FooCreateArgs = $CreateArgs<$Schema, "Foo">;
7579
export type FooCreateManyArgs = $CreateManyArgs<$Schema, "Foo">;
7680
export type FooCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Foo">;
@@ -91,6 +95,7 @@ export type FooGetPayload<Args extends $SelectIncludeOmit<$Schema, "Foo", true>,
9195
export type BarFindManyArgs = $FindManyArgs<$Schema, "Bar">;
9296
export type BarFindUniqueArgs = $FindUniqueArgs<$Schema, "Bar">;
9397
export type BarFindFirstArgs = $FindFirstArgs<$Schema, "Bar">;
98+
export type BarExistsArgs = $ExistsArgs<$Schema, "Bar">;
9499
export type BarCreateArgs = $CreateArgs<$Schema, "Bar">;
95100
export type BarCreateManyArgs = $CreateManyArgs<$Schema, "Bar">;
96101
export type BarCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Bar">;

packages/clients/tanstack-query/test/svelte-typing-test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ check(client.user.useFindUnique(() => ({ where: { id: '1' }, include: { posts: t
1818
check(client.user.useFindFirst().data?.email);
1919
check(client.user.useFindFirst().data?.$optimistic);
2020

21+
check(client.user.useExists().data);
22+
check(client.user.useExists(() => ({ where: { id: '1' } })).data);
23+
2124
check(client.user.useFindMany().data?.[0]?.email);
2225
check(client.user.useFindMany().data?.[0]?.$optimistic);
2326

packages/clients/tanstack-query/test/vue-typing-test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ check(client.user.useFindUnique({ where: { id: '1' }, include: { posts: true } }
1818
check(client.user.useFindFirst().data.value?.email);
1919
check(client.user.useFindFirst().data.value?.$optimistic);
2020

21+
check(client.user.useExists().data.value);
22+
check(client.user.useExists({ where: { id: '1' } }).data.value);
23+
2124
check(client.user.useFindMany().data.value?.[0]?.email);
2225
check(client.user.useFindMany().data.value?.[0]?.$optimistic);
2326

packages/orm/src/client/client-impl.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import { CountOperationHandler } from './crud/operations/count';
2727
import { CreateOperationHandler } from './crud/operations/create';
2828
import { DeleteOperationHandler } from './crud/operations/delete';
2929
import { FindOperationHandler } from './crud/operations/find';
30+
import { ExistsOperationHandler } from './crud/operations/exists';
3031
import { GroupByOperationHandler } from './crud/operations/group-by';
3132
import { UpdateOperationHandler } from './crud/operations/update';
3233
import { InputValidator } from './crud/validator';
@@ -598,5 +599,15 @@ function createModelCrudHandler(
598599
true,
599600
);
600601
},
602+
603+
exists: (args: unknown) => {
604+
return createPromise(
605+
'exists',
606+
'exists',
607+
args,
608+
new ExistsOperationHandler<any>(client, model, inputValidator),
609+
false,
610+
);
611+
},
601612
} as ModelOperations<any, any>;
602613
}

packages/orm/src/client/contract.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import type {
2424
DefaultModelResult,
2525
DeleteArgs,
2626
DeleteManyArgs,
27+
ExistsArgs,
2728
FindFirstArgs,
2829
FindManyArgs,
2930
FindUniqueArgs,
@@ -828,6 +829,27 @@ export type AllModelOperations<
828829
groupBy<T extends GroupByArgs<Schema, Model>>(
829830
args: Subset<T, GroupByArgs<Schema, Model>>,
830831
): ZenStackPromise<Schema, Simplify<GroupByResult<Schema, Model, T>>>;
832+
833+
/**
834+
* Checks if an entity exists.
835+
* @param args - exists args
836+
* @returns whether a matching entity was found
837+
*
838+
* @example
839+
* ```ts
840+
* // check if a user exists
841+
* await db.user.exists({
842+
* where: { id: 1 },
843+
* }); // result: `boolean`
844+
*
845+
* // check with a relation
846+
* await db.user.exists({
847+
* where: { posts: { some: { published: true } } },
848+
* }); // result: `boolean`
849+
*/
850+
exists<T extends ExistsArgs<Schema, Model>>(
851+
args?: Subset<T, ExistsArgs<Schema, Model>>,
852+
): ZenStackPromise<Schema, boolean>;
831853
};
832854

833855
export type OperationsIneligibleForDelegateModels = 'create' | 'createMany' | 'createManyAndReturn' | 'upsert';

packages/orm/src/client/crud-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,8 @@ export type FindManyArgs<Schema extends SchemaDef, Model extends GetModels<Schem
10791079

10801080
export type FindFirstArgs<Schema extends SchemaDef, Model extends GetModels<Schema>> = FindArgs<Schema, Model, true>;
10811081

1082+
export type ExistsArgs<Schema extends SchemaDef, Model extends GetModels<Schema>> = FilterArgs<Schema, Model>;
1083+
10821084
export type FindUniqueArgs<Schema extends SchemaDef, Model extends GetModels<Schema>> = {
10831085
where: WhereUniqueInput<Schema, Model>;
10841086
} & SelectIncludeOmit<Schema, Model, true>;

0 commit comments

Comments
 (0)