From a06004e498af28371b5a8a69b5d3be1376efd23e Mon Sep 17 00:00:00 2001 From: Eugen Istoc Date: Tue, 17 Mar 2026 09:03:08 -0400 Subject: [PATCH 1/4] feat(clients): add ExtResult support to TanStack Query hooks Add InferSchema, InferOptions, and InferExtResult type utilities to client-helpers. Update React, Vue, and Svelte adapters to accept ClientContract type parameter, enabling computed fields from plugins to be reflected in result types. Simplify useClientQueries API by inferring schema and options from the client type. Update sliced-client tests to use new API surface. --- packages/clients/client-helpers/src/types.ts | 20 +++ packages/clients/tanstack-query/src/react.ts | 162 ++++++++++-------- .../tanstack-query/src/svelte/index.svelte.ts | 125 ++++++++------ packages/clients/tanstack-query/src/vue.ts | 126 ++++++++------ .../test/react-sliced-client.test-d.ts | 76 ++++---- .../test/svelte-sliced-client.test-d.ts | 76 ++++---- .../test/vue-sliced-client.test-d.ts | 76 ++++---- 7 files changed, 380 insertions(+), 281 deletions(-) diff --git a/packages/clients/client-helpers/src/types.ts b/packages/clients/client-helpers/src/types.ts index da66f9483..5f30ac613 100644 --- a/packages/clients/client-helpers/src/types.ts +++ b/packages/clients/client-helpers/src/types.ts @@ -1,8 +1,28 @@ +import type { ClientContract, QueryOptions } from '@zenstackhq/orm'; +import type { SchemaDef } from '@zenstackhq/schema'; + /** * A type that represents either a value of type T or a Promise that resolves to type T. */ export type MaybePromise = T | Promise | PromiseLike; +/** + * Infers the schema definition from a client contract type, or passes through a raw SchemaDef. + */ +export type InferSchema = T extends { $schema: infer S extends SchemaDef } ? S : T extends SchemaDef ? T : never; + +/** + * Extracts the ExtResult type from a client contract, or defaults to `{}`. + */ +export type InferExtResult = T extends ClientContract ? E : {}; + +/** + * Infers query options from a client contract type, or defaults to `QueryOptions`. + */ +export type InferOptions = T extends { $options: infer O extends QueryOptions } + ? O + : QueryOptions; + /** * List of ORM write actions. */ diff --git a/packages/clients/tanstack-query/src/react.ts b/packages/clients/tanstack-query/src/react.ts index 5129750bf..ddfa49037 100644 --- a/packages/clients/tanstack-query/src/react.ts +++ b/packages/clients/tanstack-query/src/react.ts @@ -19,13 +19,14 @@ import { type UseSuspenseQueryOptions, type UseSuspenseQueryResult, } from '@tanstack/react-query'; -import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT } from '@zenstackhq/client-helpers'; +import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, type InferExtResult, type InferOptions, type InferSchema } from '@zenstackhq/client-helpers'; import { fetcher, makeUrl, marshal } from '@zenstackhq/client-helpers/fetch'; import { lowerCaseFirst } from '@zenstackhq/common-helpers'; import type { AggregateArgs, AggregateResult, BatchResult, + ClientContract, CountArgs, CountResult, CreateArgs, @@ -34,6 +35,7 @@ import type { DeleteArgs, DeleteManyArgs, ExistsArgs, + ExtResultBase, FindFirstArgs, FindManyArgs, FindUniqueArgs, @@ -68,6 +70,8 @@ import type { WithOptimistic, } from './common/types.js'; export type { FetchFn } from '@zenstackhq/client-helpers/fetch'; +export type { InferExtResult, InferOptions, InferSchema } from '@zenstackhq/client-helpers'; +export type { SchemaDef } from '@zenstackhq/schema'; type ProcedureHookFn< Schema extends SchemaDef, @@ -142,15 +146,20 @@ export type ModelMutationModelResult< TArgs, Array extends boolean = false, Options extends QueryOptions = QueryOptions, -> = Omit, TArgs>, 'mutateAsync'> & { + ExtResult extends ExtResultBase = {}, +> = Omit, TArgs>, 'mutateAsync'> & { mutateAsync( args: T, - options?: ModelMutationOptions, T>, - ): Promise>; + options?: ModelMutationOptions, T>, + ): Promise>; }; -export type ClientHooks = QueryOptions> = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; +export type ClientHooks< + Schema extends SchemaDef, + Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, +> = { + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -213,87 +222,88 @@ export type ModelQueryHooks< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = TrimSlicedOperations< Schema, Model, Options, { - useFindUnique>( - args: SelectSubset>, - options?: ModelQueryOptions | null>, - ): ModelQueryResult | null>; - - useSuspenseFindUnique>( - args: SelectSubset>, - options?: ModelSuspenseQueryOptions | null>, - ): ModelSuspenseQueryResult | null>; - - useFindFirst>( - args?: SelectSubset>, - options?: ModelQueryOptions | null>, - ): ModelQueryResult | null>; - - useSuspenseFindFirst>( - args?: SelectSubset>, - options?: ModelSuspenseQueryOptions | null>, - ): ModelSuspenseQueryResult | null>; + useFindUnique>( + args: SelectSubset>, + options?: ModelQueryOptions | null>, + ): ModelQueryResult | null>; + + useSuspenseFindUnique>( + args: SelectSubset>, + options?: ModelSuspenseQueryOptions | null>, + ): ModelSuspenseQueryResult | null>; + + useFindFirst>( + args?: SelectSubset>, + options?: ModelQueryOptions | null>, + ): ModelQueryResult | null>; + + useSuspenseFindFirst>( + args?: SelectSubset>, + options?: ModelSuspenseQueryOptions | null>, + ): ModelSuspenseQueryResult | null>; useExists>( args?: Subset>, options?: ModelQueryOptions, ): ModelQueryResult; - useFindMany>( - args?: SelectSubset>, - options?: ModelQueryOptions[]>, - ): ModelQueryResult[]>; + useFindMany>( + args?: SelectSubset>, + options?: ModelQueryOptions[]>, + ): ModelQueryResult[]>; - useSuspenseFindMany>( - args?: SelectSubset>, - options?: ModelSuspenseQueryOptions[]>, - ): ModelSuspenseQueryResult[]>; + useSuspenseFindMany>( + args?: SelectSubset>, + options?: ModelSuspenseQueryOptions[]>, + ): ModelSuspenseQueryResult[]>; - useInfiniteFindMany>( - args?: SelectSubset>, - options?: ModelInfiniteQueryOptions[]>, - ): ModelInfiniteQueryResult[]>>; + useInfiniteFindMany>( + args?: SelectSubset>, + options?: ModelInfiniteQueryOptions[]>, + ): ModelInfiniteQueryResult[]>>; - useSuspenseInfiniteFindMany>( - args?: SelectSubset>, - options?: ModelSuspenseInfiniteQueryOptions[]>, - ): ModelSuspenseInfiniteQueryResult[]>>; + useSuspenseInfiniteFindMany>( + args?: SelectSubset>, + options?: ModelSuspenseInfiniteQueryOptions[]>, + ): ModelSuspenseInfiniteQueryResult[]>>; - useCreate>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useCreate>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; useCreateMany>( options?: ModelMutationOptions, ): ModelMutationResult; - useCreateManyAndReturn>( - options?: ModelMutationOptions[], T>, - ): ModelMutationModelResult; + useCreateManyAndReturn>( + options?: ModelMutationOptions[], T>, + ): ModelMutationModelResult; - useUpdate>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useUpdate>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; useUpdateMany>( options?: ModelMutationOptions, ): ModelMutationResult; - useUpdateManyAndReturn>( - options?: ModelMutationOptions[], T>, - ): ModelMutationModelResult; + useUpdateManyAndReturn>( + options?: ModelMutationOptions[], T>, + ): ModelMutationModelResult; - useUpsert>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useUpsert>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; - useDelete>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useDelete>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; useDeleteMany>( options?: ModelMutationOptions, @@ -334,23 +344,38 @@ export type ModelQueryHooks< /** * Gets data query hooks for all models in the schema. * + * Accepts either a raw `SchemaDef` or a `ClientContract` type (e.g. `typeof db`) as the generic parameter. + * When a `ClientContract` type is provided, computed fields from plugins are reflected in the result types. + * + * @example + * ```typescript + * // Basic usage with schema + * const client = useClientQueries(schema) + * + * // With server client type for computed field support + * import type { DbType } from '~/server/db' + * const client = useClientQueries(schema) + * ``` + * * @param schema The schema. * @param options Options for all queries originated from this hook. */ -export function useClientQueries = QueryOptions>( - schema: Schema, +export function useClientQueries< + Client extends SchemaDef | ClientContract, +>( + schema: InferSchema, options?: QueryContext, -): ClientHooks { +): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { const result = Object.keys(schema.models).reduce( (acc, model) => { - (acc as any)[lowerCaseFirst(model)] = useModelQueries, Options>( - schema, - model as GetModels, + (acc as any)[lowerCaseFirst(model)] = useModelQueries( + schema as any, + model as any, options, ); return acc; }, - {} as ClientHooks, + {} as any, ); const procedures = (schema as any).procedures as Record | undefined; @@ -407,7 +432,8 @@ export function useModelQueries< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions, ->(schema: Schema, model: Model, rootOptions?: QueryContext): ModelQueryHooks { + ExtResult extends ExtResultBase = {}, +>(schema: Schema, model: Model, rootOptions?: QueryContext): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -517,7 +543,7 @@ export function useModelQueries< useSuspenseGroupBy: (args: any, options?: any) => { return useInternalSuspenseQuery(schema, modelName, 'groupBy', args, { ...rootOptions, ...options }); }, - } as ModelQueryHooks; + } as ModelQueryHooks; } export function useInternalQuery( diff --git a/packages/clients/tanstack-query/src/svelte/index.svelte.ts b/packages/clients/tanstack-query/src/svelte/index.svelte.ts index 45af47cb3..e690fcfc9 100644 --- a/packages/clients/tanstack-query/src/svelte/index.svelte.ts +++ b/packages/clients/tanstack-query/src/svelte/index.svelte.ts @@ -19,6 +19,9 @@ import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, + type InferExtResult, + type InferOptions, + type InferSchema, type InvalidationPredicate, } from '@zenstackhq/client-helpers'; import { fetcher, makeUrl, marshal } from '@zenstackhq/client-helpers/fetch'; @@ -27,6 +30,7 @@ import type { AggregateArgs, AggregateResult, BatchResult, + ClientContract, CountArgs, CountResult, CreateArgs, @@ -35,6 +39,7 @@ import type { DeleteArgs, DeleteManyArgs, ExistsArgs, + ExtResultBase, FindFirstArgs, FindManyArgs, FindUniqueArgs, @@ -69,6 +74,8 @@ import type { WithOptimistic, } from '../common/types.js'; export type { FetchFn } from '@zenstackhq/client-helpers/fetch'; +export type { InferExtResult, InferOptions, InferSchema } from '@zenstackhq/client-helpers'; +export type { SchemaDef } from '@zenstackhq/schema'; type ProcedureHookFn< Schema extends SchemaDef, @@ -139,15 +146,20 @@ export type ModelMutationModelResult< TArgs, Array extends boolean = false, Options extends QueryOptions = QueryOptions, -> = Omit, TArgs>, 'mutateAsync'> & { + ExtResult extends ExtResultBase = {}, +> = Omit, TArgs>, 'mutateAsync'> & { mutateAsync( args: T, - options?: ModelMutationOptions, T>, - ): Promise>; + options?: ModelMutationOptions, T>, + ): Promise>; }; -export type ClientHooks = QueryOptions> = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; +export type ClientHooks< + Schema extends SchemaDef, + Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, +> = { + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -200,65 +212,66 @@ export type ModelQueryHooks< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = TrimSlicedOperations< Schema, Model, Options, { - useFindUnique>( - args: Accessor>>, - options?: Accessor | null>>, - ): ModelQueryResult | null>; + useFindUnique>( + args: Accessor>>, + options?: Accessor | null>>, + ): ModelQueryResult | null>; - useFindFirst>( - args?: Accessor>>, - options?: Accessor | null>>, - ): ModelQueryResult | null>; + useFindFirst>( + args?: Accessor>>, + options?: Accessor | null>>, + ): ModelQueryResult | null>; useExists>( args?: Accessor>>, options?: Accessor>, ): ModelQueryResult; - useFindMany>( - args?: Accessor>>, - options?: Accessor[]>>, - ): ModelQueryResult[]>; + useFindMany>( + args?: Accessor>>, + options?: Accessor[]>>, + ): ModelQueryResult[]>; - useInfiniteFindMany>( - args?: Accessor>>, - options?: Accessor[]>>, - ): ModelInfiniteQueryResult[]>>; + useInfiniteFindMany>( + args?: Accessor>>, + options?: Accessor[]>>, + ): ModelInfiniteQueryResult[]>>; - useCreate>( - options?: Accessor, T>>, - ): ModelMutationModelResult; + useCreate>( + options?: Accessor, T>>, + ): ModelMutationModelResult; useCreateMany>( options?: Accessor>, ): ModelMutationResult; - useCreateManyAndReturn>( - options?: Accessor[], T>>, - ): ModelMutationModelResult; + useCreateManyAndReturn>( + options?: Accessor[], T>>, + ): ModelMutationModelResult; - useUpdate>( - options?: Accessor, T>>, - ): ModelMutationModelResult; + useUpdate>( + options?: Accessor, T>>, + ): ModelMutationModelResult; useUpdateMany>( options?: Accessor>, ): ModelMutationResult; - useUpdateManyAndReturn>( - options?: Accessor[], T>>, - ): ModelMutationModelResult; + useUpdateManyAndReturn>( + options?: Accessor[], T>>, + ): ModelMutationModelResult; - useUpsert>( - options?: Accessor, T>>, - ): ModelMutationModelResult; - useDelete>( - options?: Accessor, T>>, - ): ModelMutationModelResult; + useUpsert>( + options?: Accessor, T>>, + ): ModelMutationModelResult; + useDelete>( + options?: Accessor, T>>, + ): ModelMutationModelResult; useDeleteMany>( options?: Accessor>, @@ -283,21 +296,36 @@ export type ModelQueryHooks< /** * Gets data query hooks for all models in the schema. + * + * Accepts either a raw `SchemaDef` or a `ClientContract` type (e.g. `typeof db`) as the generic parameter. + * When a `ClientContract` type is provided, computed fields from plugins are reflected in the result types. + * + * @example + * ```typescript + * // Basic usage with schema + * const client = useClientQueries(schema) + * + * // With server client type for computed field support + * import type { DbType } from '~/server/db' + * const client = useClientQueries(schema) + * ``` */ -export function useClientQueries = QueryOptions>( - schema: Schema, +export function useClientQueries< + Client extends SchemaDef | ClientContract, +>( + schema: InferSchema, options?: Accessor, -): ClientHooks { +): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { const result = Object.keys(schema.models).reduce( (acc, model) => { - (acc as any)[lowerCaseFirst(model)] = useModelQueries, Options>( - schema, - model as GetModels, + (acc as any)[lowerCaseFirst(model)] = useModelQueries( + schema as any, + model as any, options, ); return acc; }, - {} as ClientHooks, + {} as any, ); const procedures = (schema as any).procedures as Record | undefined; @@ -347,7 +375,8 @@ export function useModelQueries< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions, ->(schema: Schema, model: Model, rootOptions?: Accessor): ModelQueryHooks { + ExtResult extends ExtResultBase = {}, +>(schema: Schema, model: Model, rootOptions?: Accessor): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -423,7 +452,7 @@ export function useModelQueries< useGroupBy: (args: any, options?: any) => { return useInternalQuery(schema, modelName, 'groupBy', args, options); }, - } as unknown as ModelQueryHooks; + } as unknown as ModelQueryHooks; } export function useInternalQuery( diff --git a/packages/clients/tanstack-query/src/vue.ts b/packages/clients/tanstack-query/src/vue.ts index b45a28333..6fb64aa3c 100644 --- a/packages/clients/tanstack-query/src/vue.ts +++ b/packages/clients/tanstack-query/src/vue.ts @@ -17,6 +17,9 @@ import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, + type InferExtResult, + type InferOptions, + type InferSchema, type InvalidationPredicate, } from '@zenstackhq/client-helpers'; import { fetcher, makeUrl, marshal } from '@zenstackhq/client-helpers/fetch'; @@ -25,6 +28,7 @@ import type { AggregateArgs, AggregateResult, BatchResult, + ClientContract, CountArgs, CountResult, CreateArgs, @@ -33,6 +37,7 @@ import type { DeleteArgs, DeleteManyArgs, ExistsArgs, + ExtResultBase, FindFirstArgs, FindManyArgs, FindUniqueArgs, @@ -67,6 +72,9 @@ import type { WithOptimistic, } from './common/types.js'; export type { FetchFn } from '@zenstackhq/client-helpers/fetch'; +export type { InferExtResult, InferOptions, InferSchema } from '@zenstackhq/client-helpers'; +export type { SchemaDef } from '@zenstackhq/schema'; + export const VueQueryContextKey = 'zenstack-vue-query-context'; type ProcedureHookFn< @@ -129,18 +137,23 @@ export type ModelMutationModelResult< TArgs, Array extends boolean = false, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = Omit< - ModelMutationResult, false, Array>, TArgs>, + ModelMutationResult, false, Array, ExtResult>, TArgs>, 'mutateAsync' > & { mutateAsync( args: T, - options?: ModelMutationOptions, T>, - ): Promise>; + options?: ModelMutationOptions, T>, + ): Promise>; }; -export type ClientHooks = QueryOptions> = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; +export type ClientHooks< + Schema extends SchemaDef, + Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, +> = { + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -202,67 +215,68 @@ export type ModelQueryHooks< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = TrimSlicedOperations< Schema, Model, Options, { - useFindUnique>( - args: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter | null>>, - ): ModelQueryResult | null>; + useFindUnique>( + args: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter | null>>, + ): ModelQueryResult | null>; - useFindFirst>( - args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter | null>>, - ): ModelQueryResult | null>; + useFindFirst>( + args?: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter | null>>, + ): ModelQueryResult | null>; useExists>( args?: MaybeRefOrGetter>>, options?: MaybeRefOrGetter>, ): ModelQueryResult; - useFindMany>( - args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter[]>>, - ): ModelQueryResult[]>; + useFindMany>( + args?: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter[]>>, + ): ModelQueryResult[]>; - useInfiniteFindMany>( - args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter[]>>, - ): ModelInfiniteQueryResult[]>>; + useInfiniteFindMany>( + args?: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter[]>>, + ): ModelInfiniteQueryResult[]>>; - useCreate>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useCreate>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; useCreateMany>( options?: MaybeRefOrGetter>, ): ModelMutationResult; - useCreateManyAndReturn>( - options?: MaybeRefOrGetter[], T>>, - ): ModelMutationModelResult; + useCreateManyAndReturn>( + options?: MaybeRefOrGetter[], T>>, + ): ModelMutationModelResult; - useUpdate>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useUpdate>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; useUpdateMany>( options?: MaybeRefOrGetter>, ): ModelMutationResult; - useUpdateManyAndReturn>( - options?: MaybeRefOrGetter[], T>>, - ): ModelMutationModelResult; + useUpdateManyAndReturn>( + options?: MaybeRefOrGetter[], T>>, + ): ModelMutationModelResult; - useUpsert>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useUpsert>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; - useDelete>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useDelete>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; useDeleteMany>( options?: MaybeRefOrGetter>, @@ -287,11 +301,26 @@ export type ModelQueryHooks< /** * Gets data query hooks for all models in the schema. + * + * Accepts either a raw `SchemaDef` or a `ClientContract` type (e.g. `typeof db`) as the generic parameter. + * When a `ClientContract` type is provided, computed fields from plugins are reflected in the result types. + * + * @example + * ```typescript + * // Basic usage with schema + * const client = useClientQueries(schema) + * + * // With server client type for computed field support + * import type { DbType } from '~/server/db' + * const client = useClientQueries(schema) + * ``` */ -export function useClientQueries = QueryOptions>( - schema: Schema, +export function useClientQueries< + Client extends SchemaDef | ClientContract, +>( + schema: InferSchema, options?: MaybeRefOrGetter, -): ClientHooks { +): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { const merge = (rootOpt: MaybeRefOrGetter | undefined, opt: MaybeRefOrGetter | undefined): any => { return computed(() => { const rootVal = toValue(rootOpt) ?? {}; @@ -302,14 +331,14 @@ export function useClientQueries { - (acc as any)[lowerCaseFirst(model)] = useModelQueries, Options>( - schema, - model as GetModels, + (acc as any)[lowerCaseFirst(model)] = useModelQueries( + schema as any, + model as any, options, ); return acc; }, - {} as ClientHooks, + {} as any, ); const procedures = (schema as any).procedures as Record | undefined; @@ -359,7 +388,8 @@ export function useModelQueries< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions, ->(schema: Schema, model: Model, rootOptions?: MaybeRefOrGetter): ModelQueryHooks { + ExtResult extends ExtResultBase = {}, +>(schema: Schema, model: Model, rootOptions?: MaybeRefOrGetter): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -441,7 +471,7 @@ export function useModelQueries< useGroupBy: (args: any, options?: any) => { return useInternalQuery(schema, modelName, 'groupBy', args, merge(rootOptions, options)); }, - } as ModelQueryHooks; + } as ModelQueryHooks; } export function useInternalQuery( diff --git a/packages/clients/tanstack-query/test/react-sliced-client.test-d.ts b/packages/clients/tanstack-query/test/react-sliced-client.test-d.ts index 8b31551d7..78b2eca0a 100644 --- a/packages/clients/tanstack-query/test/react-sliced-client.test-d.ts +++ b/packages/clients/tanstack-query/test/react-sliced-client.test-d.ts @@ -1,4 +1,4 @@ -import { ZenStackClient, type GetQueryOptions } from '@zenstackhq/orm'; +import { ZenStackClient } from '@zenstackhq/orm'; import { describe, expectTypeOf, it } from 'vitest'; import { useClientQueries } from '../src/react'; import { schema } from './schemas/basic/schema-lite'; @@ -20,7 +20,7 @@ describe('React client sliced client test', () => { }); it('works with sliced models', () => { - const client = useClientQueries>(schema); + const client = useClientQueries(schema); expectTypeOf(client).toHaveProperty('user'); expectTypeOf(client).toHaveProperty('post'); @@ -28,18 +28,17 @@ describe('React client sliced client test', () => { }); it('works with sliced operations', () => { - const client = useClientQueries< - typeof schema, - { - slicing: { - models: { - user: { - includedOperations: ['findUnique', 'findMany', 'update']; - }; - }; - }; - } - >(schema); + const _slicedOps = new ZenStackClient(schema, { + dialect: {} as any, + slicing: { + models: { + user: { + includedOperations: ['findUnique', 'findMany', 'update'], + }, + }, + }, + }); + const client = useClientQueries(schema); expectTypeOf(client.user).toHaveProperty('useFindUnique'); expectTypeOf(client.user).toHaveProperty('useFindMany'); @@ -48,22 +47,21 @@ describe('React client sliced client test', () => { }); it('works with sliced filters', () => { - const client = useClientQueries< - typeof schema, - { - slicing: { - models: { - user: { - fields: { - $all: { - includedFilterKinds: ['Equality']; - }; - }; - }; - }; - }; - } - >(schema); + const _slicedFilters = new ZenStackClient(schema, { + dialect: {} as any, + slicing: { + models: { + user: { + fields: { + $all: { + includedFilterKinds: ['Equality'], + }, + }, + }, + }, + }, + }); + const client = useClientQueries(schema); // Equality filter should be allowed client.user.useFindMany({ @@ -76,15 +74,15 @@ describe('React client sliced client test', () => { }); it('works with sliced procedures', () => { - const client = useClientQueries< - typeof procSchema, - { - slicing: { - includedProcedures: ['greet', 'sum']; - excludedProcedures: ['sum']; - }; - } - >(procSchema); + const _slicedProcs = new ZenStackClient(procSchema, { + dialect: {} as any, + procedures: {} as any, + slicing: { + includedProcedures: ['greet', 'sum'], + excludedProcedures: ['sum'], + }, + }); + const client = useClientQueries(procSchema); expectTypeOf(client.$procs).toHaveProperty('greet'); expectTypeOf(client.$procs).not.toHaveProperty('sum'); diff --git a/packages/clients/tanstack-query/test/svelte-sliced-client.test-d.ts b/packages/clients/tanstack-query/test/svelte-sliced-client.test-d.ts index 5b83f6ff4..2290536a8 100644 --- a/packages/clients/tanstack-query/test/svelte-sliced-client.test-d.ts +++ b/packages/clients/tanstack-query/test/svelte-sliced-client.test-d.ts @@ -1,4 +1,4 @@ -import { ZenStackClient, type GetQueryOptions } from '@zenstackhq/orm'; +import { ZenStackClient } from '@zenstackhq/orm'; import { describe, expectTypeOf, it } from 'vitest'; import { useClientQueries } from '../src/svelte/index.svelte'; import { schema } from './schemas/basic/schema-lite'; @@ -20,7 +20,7 @@ describe('Svelte client sliced client test', () => { }); it('works with sliced models', () => { - const client = useClientQueries>(schema); + const client = useClientQueries(schema); expectTypeOf(client).toHaveProperty('user'); expectTypeOf(client).toHaveProperty('post'); @@ -28,18 +28,17 @@ describe('Svelte client sliced client test', () => { }); it('works with sliced operations', () => { - const client = useClientQueries< - typeof schema, - { - slicing: { - models: { - user: { - includedOperations: ['findUnique', 'findMany', 'update']; - }; - }; - }; - } - >(schema); + const _slicedOps = new ZenStackClient(schema, { + dialect: {} as any, + slicing: { + models: { + user: { + includedOperations: ['findUnique', 'findMany', 'update'], + }, + }, + }, + }); + const client = useClientQueries(schema); expectTypeOf(client.user).toHaveProperty('useFindUnique'); expectTypeOf(client.user).toHaveProperty('useFindMany'); @@ -48,22 +47,21 @@ describe('Svelte client sliced client test', () => { }); it('works with sliced filters', () => { - const client = useClientQueries< - typeof schema, - { - slicing: { - models: { - user: { - fields: { - $all: { - includedFilterKinds: ['Equality']; - }; - }; - }; - }; - }; - } - >(schema); + const _slicedFilters = new ZenStackClient(schema, { + dialect: {} as any, + slicing: { + models: { + user: { + fields: { + $all: { + includedFilterKinds: ['Equality'], + }, + }, + }, + }, + }, + }); + const client = useClientQueries(schema); // Equality filter should be allowed client.user.useFindMany(() => ({ @@ -76,15 +74,15 @@ describe('Svelte client sliced client test', () => { }); it('works with sliced procedures', () => { - const client = useClientQueries< - typeof procSchema, - { - slicing: { - includedProcedures: ['greet', 'sum']; - excludedProcedures: ['sum']; - }; - } - >(procSchema); + const _slicedProcs = new ZenStackClient(procSchema, { + dialect: {} as any, + procedures: {} as any, + slicing: { + includedProcedures: ['greet', 'sum'], + excludedProcedures: ['sum'], + }, + }); + const client = useClientQueries(procSchema); expectTypeOf(client.$procs).toHaveProperty('greet'); expectTypeOf(client.$procs).not.toHaveProperty('sum'); diff --git a/packages/clients/tanstack-query/test/vue-sliced-client.test-d.ts b/packages/clients/tanstack-query/test/vue-sliced-client.test-d.ts index 5fdd11d6a..51637c955 100644 --- a/packages/clients/tanstack-query/test/vue-sliced-client.test-d.ts +++ b/packages/clients/tanstack-query/test/vue-sliced-client.test-d.ts @@ -1,4 +1,4 @@ -import { ZenStackClient, type GetQueryOptions } from '@zenstackhq/orm'; +import { ZenStackClient } from '@zenstackhq/orm'; import { describe, expectTypeOf, it } from 'vitest'; import { useClientQueries } from '../src/vue'; import { schema } from './schemas/basic/schema-lite'; @@ -20,7 +20,7 @@ describe('Vue client sliced client test', () => { }); it('works with sliced models', () => { - const client = useClientQueries>(schema); + const client = useClientQueries(schema); expectTypeOf(client).toHaveProperty('user'); expectTypeOf(client).toHaveProperty('post'); @@ -28,18 +28,17 @@ describe('Vue client sliced client test', () => { }); it('works with sliced operations', () => { - const client = useClientQueries< - typeof schema, - { - slicing: { - models: { - user: { - includedOperations: ['findUnique', 'findMany', 'update']; - }; - }; - }; - } - >(schema); + const _slicedOps = new ZenStackClient(schema, { + dialect: {} as any, + slicing: { + models: { + user: { + includedOperations: ['findUnique', 'findMany', 'update'], + }, + }, + }, + }); + const client = useClientQueries(schema); expectTypeOf(client.user).toHaveProperty('useFindUnique'); expectTypeOf(client.user).toHaveProperty('useFindMany'); @@ -48,22 +47,21 @@ describe('Vue client sliced client test', () => { }); it('works with sliced filters', () => { - const client = useClientQueries< - typeof schema, - { - slicing: { - models: { - user: { - fields: { - $all: { - includedFilterKinds: ['Equality']; - }; - }; - }; - }; - }; - } - >(schema); + const _slicedFilters = new ZenStackClient(schema, { + dialect: {} as any, + slicing: { + models: { + user: { + fields: { + $all: { + includedFilterKinds: ['Equality'], + }, + }, + }, + }, + }, + }); + const client = useClientQueries(schema); // Equality filter should be allowed client.user.useFindMany({ @@ -76,15 +74,15 @@ describe('Vue client sliced client test', () => { }); it('works with sliced procedures', () => { - const client = useClientQueries< - typeof procSchema, - { - slicing: { - includedProcedures: ['greet', 'sum']; - excludedProcedures: ['sum']; - }; - } - >(procSchema); + const _slicedProcs = new ZenStackClient(procSchema, { + dialect: {} as any, + procedures: {} as any, + slicing: { + includedProcedures: ['greet', 'sum'], + excludedProcedures: ['sum'], + }, + }); + const client = useClientQueries(procSchema); expectTypeOf(client.$procs).toHaveProperty('greet'); expectTypeOf(client.$procs).not.toHaveProperty('sum'); From d6a7bc5fa5e81a55ffff835ba74d22f7bb19d3ca Mon Sep 17 00:00:00 2001 From: Eugen Istoc Date: Tue, 17 Mar 2026 18:30:57 -0400 Subject: [PATCH 2/4] refactor(clients): address review feedback for TanStack Query hooks - Rename `Client` type parameter to `SchemaOrClient` in useClientQueries - Remove `ExtResult` type parameter from hooks types (ClientHooks, ModelQueryHooks, ModelMutationModelResult, useModelQueries) since hooks are not subject to result extension; pass `{}` directly instead - Clean up unused ExtResultBase and InferExtResult imports --- packages/clients/tanstack-query/src/react.ts | 133 +++++++++--------- .../tanstack-query/src/svelte/index.svelte.ts | 94 ++++++------- packages/clients/tanstack-query/src/vue.ts | 94 ++++++------- 3 files changed, 152 insertions(+), 169 deletions(-) diff --git a/packages/clients/tanstack-query/src/react.ts b/packages/clients/tanstack-query/src/react.ts index ddfa49037..60afc8ec1 100644 --- a/packages/clients/tanstack-query/src/react.ts +++ b/packages/clients/tanstack-query/src/react.ts @@ -19,7 +19,7 @@ import { type UseSuspenseQueryOptions, type UseSuspenseQueryResult, } from '@tanstack/react-query'; -import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, type InferExtResult, type InferOptions, type InferSchema } from '@zenstackhq/client-helpers'; +import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, type InferOptions, type InferSchema } from '@zenstackhq/client-helpers'; import { fetcher, makeUrl, marshal } from '@zenstackhq/client-helpers/fetch'; import { lowerCaseFirst } from '@zenstackhq/common-helpers'; import type { @@ -35,7 +35,6 @@ import type { DeleteArgs, DeleteManyArgs, ExistsArgs, - ExtResultBase, FindFirstArgs, FindManyArgs, FindUniqueArgs, @@ -70,7 +69,7 @@ import type { WithOptimistic, } from './common/types.js'; export type { FetchFn } from '@zenstackhq/client-helpers/fetch'; -export type { InferExtResult, InferOptions, InferSchema } from '@zenstackhq/client-helpers'; +export type { InferOptions, InferSchema } from '@zenstackhq/client-helpers'; export type { SchemaDef } from '@zenstackhq/schema'; type ProcedureHookFn< @@ -146,20 +145,18 @@ export type ModelMutationModelResult< TArgs, Array extends boolean = false, Options extends QueryOptions = QueryOptions, - ExtResult extends ExtResultBase = {}, -> = Omit, TArgs>, 'mutateAsync'> & { +> = Omit, TArgs>, 'mutateAsync'> & { mutateAsync( args: T, - options?: ModelMutationOptions, T>, - ): Promise>; + options?: ModelMutationOptions, T>, + ): Promise>; }; export type ClientHooks< Schema extends SchemaDef, Options extends QueryOptions = QueryOptions, - ExtResult extends ExtResultBase = {}, > = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -222,88 +219,87 @@ export type ModelQueryHooks< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions = QueryOptions, - ExtResult extends ExtResultBase = {}, > = TrimSlicedOperations< Schema, Model, Options, { - useFindUnique>( - args: SelectSubset>, - options?: ModelQueryOptions | null>, - ): ModelQueryResult | null>; - - useSuspenseFindUnique>( - args: SelectSubset>, - options?: ModelSuspenseQueryOptions | null>, - ): ModelSuspenseQueryResult | null>; - - useFindFirst>( - args?: SelectSubset>, - options?: ModelQueryOptions | null>, - ): ModelQueryResult | null>; - - useSuspenseFindFirst>( - args?: SelectSubset>, - options?: ModelSuspenseQueryOptions | null>, - ): ModelSuspenseQueryResult | null>; + useFindUnique>( + args: SelectSubset>, + options?: ModelQueryOptions | null>, + ): ModelQueryResult | null>; + + useSuspenseFindUnique>( + args: SelectSubset>, + options?: ModelSuspenseQueryOptions | null>, + ): ModelSuspenseQueryResult | null>; + + useFindFirst>( + args?: SelectSubset>, + options?: ModelQueryOptions | null>, + ): ModelQueryResult | null>; + + useSuspenseFindFirst>( + args?: SelectSubset>, + options?: ModelSuspenseQueryOptions | null>, + ): ModelSuspenseQueryResult | null>; useExists>( args?: Subset>, options?: ModelQueryOptions, ): ModelQueryResult; - useFindMany>( - args?: SelectSubset>, - options?: ModelQueryOptions[]>, - ): ModelQueryResult[]>; + useFindMany>( + args?: SelectSubset>, + options?: ModelQueryOptions[]>, + ): ModelQueryResult[]>; - useSuspenseFindMany>( - args?: SelectSubset>, - options?: ModelSuspenseQueryOptions[]>, - ): ModelSuspenseQueryResult[]>; + useSuspenseFindMany>( + args?: SelectSubset>, + options?: ModelSuspenseQueryOptions[]>, + ): ModelSuspenseQueryResult[]>; - useInfiniteFindMany>( - args?: SelectSubset>, - options?: ModelInfiniteQueryOptions[]>, - ): ModelInfiniteQueryResult[]>>; + useInfiniteFindMany>( + args?: SelectSubset>, + options?: ModelInfiniteQueryOptions[]>, + ): ModelInfiniteQueryResult[]>>; - useSuspenseInfiniteFindMany>( - args?: SelectSubset>, - options?: ModelSuspenseInfiniteQueryOptions[]>, - ): ModelSuspenseInfiniteQueryResult[]>>; + useSuspenseInfiniteFindMany>( + args?: SelectSubset>, + options?: ModelSuspenseInfiniteQueryOptions[]>, + ): ModelSuspenseInfiniteQueryResult[]>>; - useCreate>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useCreate>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; useCreateMany>( options?: ModelMutationOptions, ): ModelMutationResult; - useCreateManyAndReturn>( - options?: ModelMutationOptions[], T>, - ): ModelMutationModelResult; + useCreateManyAndReturn>( + options?: ModelMutationOptions[], T>, + ): ModelMutationModelResult; - useUpdate>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useUpdate>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; useUpdateMany>( options?: ModelMutationOptions, ): ModelMutationResult; - useUpdateManyAndReturn>( - options?: ModelMutationOptions[], T>, - ): ModelMutationModelResult; + useUpdateManyAndReturn>( + options?: ModelMutationOptions[], T>, + ): ModelMutationModelResult; - useUpsert>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useUpsert>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; - useDelete>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useDelete>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; useDeleteMany>( options?: ModelMutationOptions, @@ -361,11 +357,11 @@ export type ModelQueryHooks< * @param options Options for all queries originated from this hook. */ export function useClientQueries< - Client extends SchemaDef | ClientContract, + SchemaOrClient extends SchemaDef | ClientContract, >( - schema: InferSchema, + schema: InferSchema, options?: QueryContext, -): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { +): ClientHooks, InferOptions>> { const result = Object.keys(schema.models).reduce( (acc, model) => { (acc as any)[lowerCaseFirst(model)] = useModelQueries( @@ -432,8 +428,7 @@ export function useModelQueries< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions, - ExtResult extends ExtResultBase = {}, ->(schema: Schema, model: Model, rootOptions?: QueryContext): ModelQueryHooks { +>(schema: Schema, model: Model, rootOptions?: QueryContext): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -543,7 +538,7 @@ export function useModelQueries< useSuspenseGroupBy: (args: any, options?: any) => { return useInternalSuspenseQuery(schema, modelName, 'groupBy', args, { ...rootOptions, ...options }); }, - } as ModelQueryHooks; + } as ModelQueryHooks; } export function useInternalQuery( diff --git a/packages/clients/tanstack-query/src/svelte/index.svelte.ts b/packages/clients/tanstack-query/src/svelte/index.svelte.ts index e690fcfc9..c0cb00033 100644 --- a/packages/clients/tanstack-query/src/svelte/index.svelte.ts +++ b/packages/clients/tanstack-query/src/svelte/index.svelte.ts @@ -19,7 +19,6 @@ import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, - type InferExtResult, type InferOptions, type InferSchema, type InvalidationPredicate, @@ -39,7 +38,6 @@ import type { DeleteArgs, DeleteManyArgs, ExistsArgs, - ExtResultBase, FindFirstArgs, FindManyArgs, FindUniqueArgs, @@ -74,7 +72,7 @@ import type { WithOptimistic, } from '../common/types.js'; export type { FetchFn } from '@zenstackhq/client-helpers/fetch'; -export type { InferExtResult, InferOptions, InferSchema } from '@zenstackhq/client-helpers'; +export type { InferOptions, InferSchema } from '@zenstackhq/client-helpers'; export type { SchemaDef } from '@zenstackhq/schema'; type ProcedureHookFn< @@ -146,20 +144,18 @@ export type ModelMutationModelResult< TArgs, Array extends boolean = false, Options extends QueryOptions = QueryOptions, - ExtResult extends ExtResultBase = {}, -> = Omit, TArgs>, 'mutateAsync'> & { +> = Omit, TArgs>, 'mutateAsync'> & { mutateAsync( args: T, - options?: ModelMutationOptions, T>, - ): Promise>; + options?: ModelMutationOptions, T>, + ): Promise>; }; export type ClientHooks< Schema extends SchemaDef, Options extends QueryOptions = QueryOptions, - ExtResult extends ExtResultBase = {}, > = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -212,66 +208,65 @@ export type ModelQueryHooks< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions = QueryOptions, - ExtResult extends ExtResultBase = {}, > = TrimSlicedOperations< Schema, Model, Options, { - useFindUnique>( - args: Accessor>>, - options?: Accessor | null>>, - ): ModelQueryResult | null>; + useFindUnique>( + args: Accessor>>, + options?: Accessor | null>>, + ): ModelQueryResult | null>; - useFindFirst>( - args?: Accessor>>, - options?: Accessor | null>>, - ): ModelQueryResult | null>; + useFindFirst>( + args?: Accessor>>, + options?: Accessor | null>>, + ): ModelQueryResult | null>; useExists>( args?: Accessor>>, options?: Accessor>, ): ModelQueryResult; - useFindMany>( - args?: Accessor>>, - options?: Accessor[]>>, - ): ModelQueryResult[]>; + useFindMany>( + args?: Accessor>>, + options?: Accessor[]>>, + ): ModelQueryResult[]>; - useInfiniteFindMany>( - args?: Accessor>>, - options?: Accessor[]>>, - ): ModelInfiniteQueryResult[]>>; + useInfiniteFindMany>( + args?: Accessor>>, + options?: Accessor[]>>, + ): ModelInfiniteQueryResult[]>>; - useCreate>( - options?: Accessor, T>>, - ): ModelMutationModelResult; + useCreate>( + options?: Accessor, T>>, + ): ModelMutationModelResult; useCreateMany>( options?: Accessor>, ): ModelMutationResult; - useCreateManyAndReturn>( - options?: Accessor[], T>>, - ): ModelMutationModelResult; + useCreateManyAndReturn>( + options?: Accessor[], T>>, + ): ModelMutationModelResult; - useUpdate>( - options?: Accessor, T>>, - ): ModelMutationModelResult; + useUpdate>( + options?: Accessor, T>>, + ): ModelMutationModelResult; useUpdateMany>( options?: Accessor>, ): ModelMutationResult; - useUpdateManyAndReturn>( - options?: Accessor[], T>>, - ): ModelMutationModelResult; + useUpdateManyAndReturn>( + options?: Accessor[], T>>, + ): ModelMutationModelResult; - useUpsert>( - options?: Accessor, T>>, - ): ModelMutationModelResult; - useDelete>( - options?: Accessor, T>>, - ): ModelMutationModelResult; + useUpsert>( + options?: Accessor, T>>, + ): ModelMutationModelResult; + useDelete>( + options?: Accessor, T>>, + ): ModelMutationModelResult; useDeleteMany>( options?: Accessor>, @@ -311,11 +306,11 @@ export type ModelQueryHooks< * ``` */ export function useClientQueries< - Client extends SchemaDef | ClientContract, + SchemaOrClient extends SchemaDef | ClientContract, >( - schema: InferSchema, + schema: InferSchema, options?: Accessor, -): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { +): ClientHooks, InferOptions>> { const result = Object.keys(schema.models).reduce( (acc, model) => { (acc as any)[lowerCaseFirst(model)] = useModelQueries( @@ -375,8 +370,7 @@ export function useModelQueries< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions, - ExtResult extends ExtResultBase = {}, ->(schema: Schema, model: Model, rootOptions?: Accessor): ModelQueryHooks { +>(schema: Schema, model: Model, rootOptions?: Accessor): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -452,7 +446,7 @@ export function useModelQueries< useGroupBy: (args: any, options?: any) => { return useInternalQuery(schema, modelName, 'groupBy', args, options); }, - } as unknown as ModelQueryHooks; + } as unknown as ModelQueryHooks; } export function useInternalQuery( diff --git a/packages/clients/tanstack-query/src/vue.ts b/packages/clients/tanstack-query/src/vue.ts index 6fb64aa3c..ab7a34238 100644 --- a/packages/clients/tanstack-query/src/vue.ts +++ b/packages/clients/tanstack-query/src/vue.ts @@ -17,7 +17,6 @@ import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, - type InferExtResult, type InferOptions, type InferSchema, type InvalidationPredicate, @@ -37,7 +36,6 @@ import type { DeleteArgs, DeleteManyArgs, ExistsArgs, - ExtResultBase, FindFirstArgs, FindManyArgs, FindUniqueArgs, @@ -72,7 +70,7 @@ import type { WithOptimistic, } from './common/types.js'; export type { FetchFn } from '@zenstackhq/client-helpers/fetch'; -export type { InferExtResult, InferOptions, InferSchema } from '@zenstackhq/client-helpers'; +export type { InferOptions, InferSchema } from '@zenstackhq/client-helpers'; export type { SchemaDef } from '@zenstackhq/schema'; export const VueQueryContextKey = 'zenstack-vue-query-context'; @@ -137,23 +135,21 @@ export type ModelMutationModelResult< TArgs, Array extends boolean = false, Options extends QueryOptions = QueryOptions, - ExtResult extends ExtResultBase = {}, > = Omit< - ModelMutationResult, false, Array, ExtResult>, TArgs>, + ModelMutationResult, false, Array, {}>, TArgs>, 'mutateAsync' > & { mutateAsync( args: T, - options?: ModelMutationOptions, T>, - ): Promise>; + options?: ModelMutationOptions, T>, + ): Promise>; }; export type ClientHooks< Schema extends SchemaDef, Options extends QueryOptions = QueryOptions, - ExtResult extends ExtResultBase = {}, > = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -215,68 +211,67 @@ export type ModelQueryHooks< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions = QueryOptions, - ExtResult extends ExtResultBase = {}, > = TrimSlicedOperations< Schema, Model, Options, { - useFindUnique>( - args: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter | null>>, - ): ModelQueryResult | null>; + useFindUnique>( + args: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter | null>>, + ): ModelQueryResult | null>; - useFindFirst>( - args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter | null>>, - ): ModelQueryResult | null>; + useFindFirst>( + args?: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter | null>>, + ): ModelQueryResult | null>; useExists>( args?: MaybeRefOrGetter>>, options?: MaybeRefOrGetter>, ): ModelQueryResult; - useFindMany>( - args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter[]>>, - ): ModelQueryResult[]>; + useFindMany>( + args?: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter[]>>, + ): ModelQueryResult[]>; - useInfiniteFindMany>( - args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter[]>>, - ): ModelInfiniteQueryResult[]>>; + useInfiniteFindMany>( + args?: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter[]>>, + ): ModelInfiniteQueryResult[]>>; - useCreate>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useCreate>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; useCreateMany>( options?: MaybeRefOrGetter>, ): ModelMutationResult; - useCreateManyAndReturn>( - options?: MaybeRefOrGetter[], T>>, - ): ModelMutationModelResult; + useCreateManyAndReturn>( + options?: MaybeRefOrGetter[], T>>, + ): ModelMutationModelResult; - useUpdate>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useUpdate>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; useUpdateMany>( options?: MaybeRefOrGetter>, ): ModelMutationResult; - useUpdateManyAndReturn>( - options?: MaybeRefOrGetter[], T>>, - ): ModelMutationModelResult; + useUpdateManyAndReturn>( + options?: MaybeRefOrGetter[], T>>, + ): ModelMutationModelResult; - useUpsert>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useUpsert>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; - useDelete>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useDelete>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; useDeleteMany>( options?: MaybeRefOrGetter>, @@ -316,11 +311,11 @@ export type ModelQueryHooks< * ``` */ export function useClientQueries< - Client extends SchemaDef | ClientContract, + SchemaOrClient extends SchemaDef | ClientContract, >( - schema: InferSchema, + schema: InferSchema, options?: MaybeRefOrGetter, -): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { +): ClientHooks, InferOptions>> { const merge = (rootOpt: MaybeRefOrGetter | undefined, opt: MaybeRefOrGetter | undefined): any => { return computed(() => { const rootVal = toValue(rootOpt) ?? {}; @@ -388,8 +383,7 @@ export function useModelQueries< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions, - ExtResult extends ExtResultBase = {}, ->(schema: Schema, model: Model, rootOptions?: MaybeRefOrGetter): ModelQueryHooks { +>(schema: Schema, model: Model, rootOptions?: MaybeRefOrGetter): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -471,7 +465,7 @@ export function useModelQueries< useGroupBy: (args: any, options?: any) => { return useInternalQuery(schema, modelName, 'groupBy', args, merge(rootOptions, options)); }, - } as ModelQueryHooks; + } as ModelQueryHooks; } export function useInternalQuery( From 346799a6911b7d30800fc296f51ae119826e4857 Mon Sep 17 00:00:00 2001 From: Eugen Istoc Date: Tue, 17 Mar 2026 18:38:27 -0400 Subject: [PATCH 3/4] fix(clients): use Options generic consistently in Vue ModelMutationModelResult The base mutation result type was hardcoding QueryOptions instead of using the Options generic parameter, breaking consistency with React and Svelte adapters. --- packages/clients/tanstack-query/src/vue.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/clients/tanstack-query/src/vue.ts b/packages/clients/tanstack-query/src/vue.ts index ab7a34238..dd8cc0418 100644 --- a/packages/clients/tanstack-query/src/vue.ts +++ b/packages/clients/tanstack-query/src/vue.ts @@ -136,7 +136,7 @@ export type ModelMutationModelResult< Array extends boolean = false, Options extends QueryOptions = QueryOptions, > = Omit< - ModelMutationResult, false, Array, {}>, TArgs>, + ModelMutationResult, TArgs>, 'mutateAsync' > & { mutateAsync( From d5aead0ebff1fa355427a6dbe44d798b91a726a5 Mon Sep 17 00:00:00 2001 From: Eugen Istoc Date: Wed, 18 Mar 2026 07:33:23 -0400 Subject: [PATCH 4/4] fix(clients): restore ExtResult for model hooks, keep removed for procedures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit over-applied the review feedback — ExtResult was removed from all hooks, but the reviewer intended it only for custom procedure hooks. Regular model hooks should carry ExtResult typing for plugin-computed field support. --- packages/clients/tanstack-query/src/react.ts | 129 +++++++++--------- .../tanstack-query/src/svelte/index.svelte.ts | 90 ++++++------ packages/clients/tanstack-query/src/vue.ts | 90 ++++++------ 3 files changed, 163 insertions(+), 146 deletions(-) diff --git a/packages/clients/tanstack-query/src/react.ts b/packages/clients/tanstack-query/src/react.ts index 60afc8ec1..e84aa7e09 100644 --- a/packages/clients/tanstack-query/src/react.ts +++ b/packages/clients/tanstack-query/src/react.ts @@ -19,7 +19,7 @@ import { type UseSuspenseQueryOptions, type UseSuspenseQueryResult, } from '@tanstack/react-query'; -import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, type InferOptions, type InferSchema } from '@zenstackhq/client-helpers'; +import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, type InferExtResult, type InferOptions, type InferSchema } from '@zenstackhq/client-helpers'; import { fetcher, makeUrl, marshal } from '@zenstackhq/client-helpers/fetch'; import { lowerCaseFirst } from '@zenstackhq/common-helpers'; import type { @@ -35,6 +35,7 @@ import type { DeleteArgs, DeleteManyArgs, ExistsArgs, + ExtResultBase, FindFirstArgs, FindManyArgs, FindUniqueArgs, @@ -69,7 +70,7 @@ import type { WithOptimistic, } from './common/types.js'; export type { FetchFn } from '@zenstackhq/client-helpers/fetch'; -export type { InferOptions, InferSchema } from '@zenstackhq/client-helpers'; +export type { InferExtResult, InferOptions, InferSchema } from '@zenstackhq/client-helpers'; export type { SchemaDef } from '@zenstackhq/schema'; type ProcedureHookFn< @@ -145,18 +146,20 @@ export type ModelMutationModelResult< TArgs, Array extends boolean = false, Options extends QueryOptions = QueryOptions, -> = Omit, TArgs>, 'mutateAsync'> & { + ExtResult extends ExtResultBase = {}, +> = Omit, TArgs>, 'mutateAsync'> & { mutateAsync( args: T, - options?: ModelMutationOptions, T>, - ): Promise>; + options?: ModelMutationOptions, T>, + ): Promise>; }; export type ClientHooks< Schema extends SchemaDef, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -219,87 +222,88 @@ export type ModelQueryHooks< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = TrimSlicedOperations< Schema, Model, Options, { - useFindUnique>( - args: SelectSubset>, - options?: ModelQueryOptions | null>, - ): ModelQueryResult | null>; - - useSuspenseFindUnique>( - args: SelectSubset>, - options?: ModelSuspenseQueryOptions | null>, - ): ModelSuspenseQueryResult | null>; - - useFindFirst>( - args?: SelectSubset>, - options?: ModelQueryOptions | null>, - ): ModelQueryResult | null>; - - useSuspenseFindFirst>( - args?: SelectSubset>, - options?: ModelSuspenseQueryOptions | null>, - ): ModelSuspenseQueryResult | null>; + useFindUnique>( + args: SelectSubset>, + options?: ModelQueryOptions | null>, + ): ModelQueryResult | null>; + + useSuspenseFindUnique>( + args: SelectSubset>, + options?: ModelSuspenseQueryOptions | null>, + ): ModelSuspenseQueryResult | null>; + + useFindFirst>( + args?: SelectSubset>, + options?: ModelQueryOptions | null>, + ): ModelQueryResult | null>; + + useSuspenseFindFirst>( + args?: SelectSubset>, + options?: ModelSuspenseQueryOptions | null>, + ): ModelSuspenseQueryResult | null>; useExists>( args?: Subset>, options?: ModelQueryOptions, ): ModelQueryResult; - useFindMany>( - args?: SelectSubset>, - options?: ModelQueryOptions[]>, - ): ModelQueryResult[]>; + useFindMany>( + args?: SelectSubset>, + options?: ModelQueryOptions[]>, + ): ModelQueryResult[]>; - useSuspenseFindMany>( - args?: SelectSubset>, - options?: ModelSuspenseQueryOptions[]>, - ): ModelSuspenseQueryResult[]>; + useSuspenseFindMany>( + args?: SelectSubset>, + options?: ModelSuspenseQueryOptions[]>, + ): ModelSuspenseQueryResult[]>; - useInfiniteFindMany>( - args?: SelectSubset>, - options?: ModelInfiniteQueryOptions[]>, - ): ModelInfiniteQueryResult[]>>; + useInfiniteFindMany>( + args?: SelectSubset>, + options?: ModelInfiniteQueryOptions[]>, + ): ModelInfiniteQueryResult[]>>; - useSuspenseInfiniteFindMany>( - args?: SelectSubset>, - options?: ModelSuspenseInfiniteQueryOptions[]>, - ): ModelSuspenseInfiniteQueryResult[]>>; + useSuspenseInfiniteFindMany>( + args?: SelectSubset>, + options?: ModelSuspenseInfiniteQueryOptions[]>, + ): ModelSuspenseInfiniteQueryResult[]>>; - useCreate>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useCreate>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; useCreateMany>( options?: ModelMutationOptions, ): ModelMutationResult; - useCreateManyAndReturn>( - options?: ModelMutationOptions[], T>, - ): ModelMutationModelResult; + useCreateManyAndReturn>( + options?: ModelMutationOptions[], T>, + ): ModelMutationModelResult; - useUpdate>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useUpdate>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; useUpdateMany>( options?: ModelMutationOptions, ): ModelMutationResult; - useUpdateManyAndReturn>( - options?: ModelMutationOptions[], T>, - ): ModelMutationModelResult; + useUpdateManyAndReturn>( + options?: ModelMutationOptions[], T>, + ): ModelMutationModelResult; - useUpsert>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useUpsert>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; - useDelete>( - options?: ModelMutationOptions, T>, - ): ModelMutationModelResult; + useDelete>( + options?: ModelMutationOptions, T>, + ): ModelMutationModelResult; useDeleteMany>( options?: ModelMutationOptions, @@ -361,7 +365,7 @@ export function useClientQueries< >( schema: InferSchema, options?: QueryContext, -): ClientHooks, InferOptions>> { +): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { const result = Object.keys(schema.models).reduce( (acc, model) => { (acc as any)[lowerCaseFirst(model)] = useModelQueries( @@ -428,7 +432,8 @@ export function useModelQueries< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions, ->(schema: Schema, model: Model, rootOptions?: QueryContext): ModelQueryHooks { + ExtResult extends ExtResultBase = {}, +>(schema: Schema, model: Model, rootOptions?: QueryContext): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -538,7 +543,7 @@ export function useModelQueries< useSuspenseGroupBy: (args: any, options?: any) => { return useInternalSuspenseQuery(schema, modelName, 'groupBy', args, { ...rootOptions, ...options }); }, - } as ModelQueryHooks; + } as ModelQueryHooks; } export function useInternalQuery( diff --git a/packages/clients/tanstack-query/src/svelte/index.svelte.ts b/packages/clients/tanstack-query/src/svelte/index.svelte.ts index c0cb00033..9ddfe40e2 100644 --- a/packages/clients/tanstack-query/src/svelte/index.svelte.ts +++ b/packages/clients/tanstack-query/src/svelte/index.svelte.ts @@ -19,6 +19,7 @@ import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, + type InferExtResult, type InferOptions, type InferSchema, type InvalidationPredicate, @@ -38,6 +39,7 @@ import type { DeleteArgs, DeleteManyArgs, ExistsArgs, + ExtResultBase, FindFirstArgs, FindManyArgs, FindUniqueArgs, @@ -72,7 +74,7 @@ import type { WithOptimistic, } from '../common/types.js'; export type { FetchFn } from '@zenstackhq/client-helpers/fetch'; -export type { InferOptions, InferSchema } from '@zenstackhq/client-helpers'; +export type { InferExtResult, InferOptions, InferSchema } from '@zenstackhq/client-helpers'; export type { SchemaDef } from '@zenstackhq/schema'; type ProcedureHookFn< @@ -144,18 +146,20 @@ export type ModelMutationModelResult< TArgs, Array extends boolean = false, Options extends QueryOptions = QueryOptions, -> = Omit, TArgs>, 'mutateAsync'> & { + ExtResult extends ExtResultBase = {}, +> = Omit, TArgs>, 'mutateAsync'> & { mutateAsync( args: T, - options?: ModelMutationOptions, T>, - ): Promise>; + options?: ModelMutationOptions, T>, + ): Promise>; }; export type ClientHooks< Schema extends SchemaDef, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -208,65 +212,66 @@ export type ModelQueryHooks< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = TrimSlicedOperations< Schema, Model, Options, { - useFindUnique>( - args: Accessor>>, - options?: Accessor | null>>, - ): ModelQueryResult | null>; + useFindUnique>( + args: Accessor>>, + options?: Accessor | null>>, + ): ModelQueryResult | null>; - useFindFirst>( - args?: Accessor>>, - options?: Accessor | null>>, - ): ModelQueryResult | null>; + useFindFirst>( + args?: Accessor>>, + options?: Accessor | null>>, + ): ModelQueryResult | null>; useExists>( args?: Accessor>>, options?: Accessor>, ): ModelQueryResult; - useFindMany>( - args?: Accessor>>, - options?: Accessor[]>>, - ): ModelQueryResult[]>; + useFindMany>( + args?: Accessor>>, + options?: Accessor[]>>, + ): ModelQueryResult[]>; - useInfiniteFindMany>( - args?: Accessor>>, - options?: Accessor[]>>, - ): ModelInfiniteQueryResult[]>>; + useInfiniteFindMany>( + args?: Accessor>>, + options?: Accessor[]>>, + ): ModelInfiniteQueryResult[]>>; - useCreate>( - options?: Accessor, T>>, - ): ModelMutationModelResult; + useCreate>( + options?: Accessor, T>>, + ): ModelMutationModelResult; useCreateMany>( options?: Accessor>, ): ModelMutationResult; - useCreateManyAndReturn>( - options?: Accessor[], T>>, - ): ModelMutationModelResult; + useCreateManyAndReturn>( + options?: Accessor[], T>>, + ): ModelMutationModelResult; - useUpdate>( - options?: Accessor, T>>, - ): ModelMutationModelResult; + useUpdate>( + options?: Accessor, T>>, + ): ModelMutationModelResult; useUpdateMany>( options?: Accessor>, ): ModelMutationResult; - useUpdateManyAndReturn>( - options?: Accessor[], T>>, - ): ModelMutationModelResult; + useUpdateManyAndReturn>( + options?: Accessor[], T>>, + ): ModelMutationModelResult; - useUpsert>( - options?: Accessor, T>>, - ): ModelMutationModelResult; - useDelete>( - options?: Accessor, T>>, - ): ModelMutationModelResult; + useUpsert>( + options?: Accessor, T>>, + ): ModelMutationModelResult; + useDelete>( + options?: Accessor, T>>, + ): ModelMutationModelResult; useDeleteMany>( options?: Accessor>, @@ -310,7 +315,7 @@ export function useClientQueries< >( schema: InferSchema, options?: Accessor, -): ClientHooks, InferOptions>> { +): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { const result = Object.keys(schema.models).reduce( (acc, model) => { (acc as any)[lowerCaseFirst(model)] = useModelQueries( @@ -370,7 +375,8 @@ export function useModelQueries< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions, ->(schema: Schema, model: Model, rootOptions?: Accessor): ModelQueryHooks { + ExtResult extends ExtResultBase = {}, +>(schema: Schema, model: Model, rootOptions?: Accessor): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -446,7 +452,7 @@ export function useModelQueries< useGroupBy: (args: any, options?: any) => { return useInternalQuery(schema, modelName, 'groupBy', args, options); }, - } as unknown as ModelQueryHooks; + } as unknown as ModelQueryHooks; } export function useInternalQuery( diff --git a/packages/clients/tanstack-query/src/vue.ts b/packages/clients/tanstack-query/src/vue.ts index dd8cc0418..4b0e8a682 100644 --- a/packages/clients/tanstack-query/src/vue.ts +++ b/packages/clients/tanstack-query/src/vue.ts @@ -17,6 +17,7 @@ import { createInvalidator, createOptimisticUpdater, DEFAULT_QUERY_ENDPOINT, + type InferExtResult, type InferOptions, type InferSchema, type InvalidationPredicate, @@ -36,6 +37,7 @@ import type { DeleteArgs, DeleteManyArgs, ExistsArgs, + ExtResultBase, FindFirstArgs, FindManyArgs, FindUniqueArgs, @@ -70,7 +72,7 @@ import type { WithOptimistic, } from './common/types.js'; export type { FetchFn } from '@zenstackhq/client-helpers/fetch'; -export type { InferOptions, InferSchema } from '@zenstackhq/client-helpers'; +export type { InferExtResult, InferOptions, InferSchema } from '@zenstackhq/client-helpers'; export type { SchemaDef } from '@zenstackhq/schema'; export const VueQueryContextKey = 'zenstack-vue-query-context'; @@ -135,21 +137,23 @@ export type ModelMutationModelResult< TArgs, Array extends boolean = false, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = Omit< - ModelMutationResult, TArgs>, + ModelMutationResult, TArgs>, 'mutateAsync' > & { mutateAsync( args: T, - options?: ModelMutationOptions, T>, - ): Promise>; + options?: ModelMutationOptions, T>, + ): Promise>; }; export type ClientHooks< Schema extends SchemaDef, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = { - [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; + [Model in GetSlicedModels as `${Uncapitalize}`]: ModelQueryHooks; } & ProcedureHooks; type ProcedureHookGroup> = { @@ -211,67 +215,68 @@ export type ModelQueryHooks< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions = QueryOptions, + ExtResult extends ExtResultBase = {}, > = TrimSlicedOperations< Schema, Model, Options, { - useFindUnique>( - args: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter | null>>, - ): ModelQueryResult | null>; + useFindUnique>( + args: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter | null>>, + ): ModelQueryResult | null>; - useFindFirst>( - args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter | null>>, - ): ModelQueryResult | null>; + useFindFirst>( + args?: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter | null>>, + ): ModelQueryResult | null>; useExists>( args?: MaybeRefOrGetter>>, options?: MaybeRefOrGetter>, ): ModelQueryResult; - useFindMany>( - args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter[]>>, - ): ModelQueryResult[]>; + useFindMany>( + args?: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter[]>>, + ): ModelQueryResult[]>; - useInfiniteFindMany>( - args?: MaybeRefOrGetter>>, - options?: MaybeRefOrGetter[]>>, - ): ModelInfiniteQueryResult[]>>; + useInfiniteFindMany>( + args?: MaybeRefOrGetter>>, + options?: MaybeRefOrGetter[]>>, + ): ModelInfiniteQueryResult[]>>; - useCreate>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useCreate>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; useCreateMany>( options?: MaybeRefOrGetter>, ): ModelMutationResult; - useCreateManyAndReturn>( - options?: MaybeRefOrGetter[], T>>, - ): ModelMutationModelResult; + useCreateManyAndReturn>( + options?: MaybeRefOrGetter[], T>>, + ): ModelMutationModelResult; - useUpdate>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useUpdate>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; useUpdateMany>( options?: MaybeRefOrGetter>, ): ModelMutationResult; - useUpdateManyAndReturn>( - options?: MaybeRefOrGetter[], T>>, - ): ModelMutationModelResult; + useUpdateManyAndReturn>( + options?: MaybeRefOrGetter[], T>>, + ): ModelMutationModelResult; - useUpsert>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useUpsert>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; - useDelete>( - options?: MaybeRefOrGetter, T>>, - ): ModelMutationModelResult; + useDelete>( + options?: MaybeRefOrGetter, T>>, + ): ModelMutationModelResult; useDeleteMany>( options?: MaybeRefOrGetter>, @@ -315,7 +320,7 @@ export function useClientQueries< >( schema: InferSchema, options?: MaybeRefOrGetter, -): ClientHooks, InferOptions>> { +): ClientHooks, InferOptions>, InferExtResult extends ExtResultBase> ? InferExtResult : {}> { const merge = (rootOpt: MaybeRefOrGetter | undefined, opt: MaybeRefOrGetter | undefined): any => { return computed(() => { const rootVal = toValue(rootOpt) ?? {}; @@ -383,7 +388,8 @@ export function useModelQueries< Schema extends SchemaDef, Model extends GetModels, Options extends QueryOptions, ->(schema: Schema, model: Model, rootOptions?: MaybeRefOrGetter): ModelQueryHooks { + ExtResult extends ExtResultBase = {}, +>(schema: Schema, model: Model, rootOptions?: MaybeRefOrGetter): ModelQueryHooks { const modelDef = Object.values(schema.models).find((m) => m.name.toLowerCase() === model.toLowerCase()); if (!modelDef) { throw new Error(`Model "${model}" not found in schema`); @@ -465,7 +471,7 @@ export function useModelQueries< useGroupBy: (args: any, options?: any) => { return useInternalQuery(schema, modelName, 'groupBy', args, merge(rootOptions, options)); }, - } as ModelQueryHooks; + } as ModelQueryHooks; } export function useInternalQuery(