@zenstackhq/tanstack-query 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/generator.js +29 -8
- package/generator.js.map +1 -1
- package/package.json +5 -5
- package/runtime/{common-5e18c135.d.ts → common-82ef6965.d.ts} +13 -2
- package/runtime/index.d.mts +1 -1
- package/runtime/index.d.ts +1 -1
- package/runtime/index.js +2 -2
- package/runtime/index.js.map +1 -1
- package/runtime/index.mjs +7 -3
- package/runtime/index.mjs.map +1 -1
- package/runtime/react.d.mts +8 -3
- package/runtime/react.d.ts +8 -3
- package/runtime/react.js +94 -12
- package/runtime/react.js.map +1 -1
- package/runtime/react.mjs +99 -13
- package/runtime/react.mjs.map +1 -1
- package/runtime/svelte.d.mts +8 -3
- package/runtime/svelte.d.ts +8 -3
- package/runtime/svelte.js +99 -10
- package/runtime/svelte.js.map +1 -1
- package/runtime/svelte.mjs +104 -11
- package/runtime/svelte.mjs.map +1 -1
- package/runtime/vue.d.mts +9 -3
- package/runtime/vue.d.ts +9 -3
- package/runtime/vue.js +94 -12
- package/runtime/vue.js.map +1 -1
- package/runtime/vue.mjs +99 -13
- package/runtime/vue.mjs.map +1 -1
- package/runtime-v5/{common-5e18c135.d.ts → common-82ef6965.d.ts} +13 -2
- package/runtime-v5/index.d.mts +1 -1
- package/runtime-v5/index.d.ts +1 -1
- package/runtime-v5/index.js +2 -2
- package/runtime-v5/index.js.map +1 -1
- package/runtime-v5/index.mjs +7 -3
- package/runtime-v5/index.mjs.map +1 -1
- package/runtime-v5/react.d.mts +19 -3
- package/runtime-v5/react.d.ts +19 -3
- package/runtime-v5/react.js +94 -12
- package/runtime-v5/react.js.map +1 -1
- package/runtime-v5/react.mjs +99 -13
- package/runtime-v5/react.mjs.map +1 -1
- package/runtime-v5/svelte.d.mts +5 -3
- package/runtime-v5/svelte.d.ts +5 -3
- package/runtime-v5/svelte.js +94 -12
- package/runtime-v5/svelte.js.map +1 -1
- package/runtime-v5/svelte.mjs +99 -13
- package/runtime-v5/svelte.mjs.map +1 -1
- package/runtime-v5/vue.d.mts +9 -3
- package/runtime-v5/vue.d.ts +9 -3
- package/runtime-v5/vue.js +94 -12
- package/runtime-v5/vue.js.map +1 -1
- package/runtime-v5/vue.mjs +99 -13
- package/runtime-v5/vue.mjs.map +1 -1
package/runtime/svelte.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/svelte.ts","../../src/runtime/common.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n createInfiniteQuery,\n createMutation,\n createQuery,\n useQueryClient,\n type CreateInfiniteQueryOptions,\n type MutationOptions,\n type QueryOptions,\n} from '@tanstack/svelte-query';\nimport { ModelMeta } from '@zenstackhq/runtime/cross';\nimport { getContext, setContext } from 'svelte';\nimport {\n APIContext,\n DEFAULT_QUERY_ENDPOINT,\n FetchFn,\n QUERY_KEY_PREFIX,\n fetcher,\n makeUrl,\n marshal,\n setupInvalidation,\n} from './common';\n\nexport { APIContext as RequestHandlerContext } from './common';\n\n/**\n * Key for setting and getting the global query context.\n */\nexport const SvelteQueryContextKey = 'zenstack-svelte-query-context';\n\n/**\n * Set context for the generated TanStack Query hooks.\n */\nexport function setHooksContext(context: APIContext) {\n setContext(SvelteQueryContextKey, context);\n}\n\n/**\n * Hooks context.\n */\nexport function getHooksContext() {\n const { endpoint, ...rest } = getContext<APIContext>(SvelteQueryContextKey);\n return { endpoint: endpoint ?? DEFAULT_QUERY_ENDPOINT, ...rest };\n}\n\n/**\n * Creates a svelte-query query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The svelte-query options object\n * @returns useQuery hook\n */\nexport function useModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: Omit<QueryOptions<R>, 'queryKey'>,\n fetch?: FetchFn\n) {\n const reqUrl = makeUrl(url, args);\n return createQuery<R>({\n queryKey: [QUERY_KEY_PREFIX + model, url, args],\n queryFn: () => fetcher<R, false>(reqUrl, undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a svelte-query infinite query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The initial request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The svelte-query infinite query options object\n * @returns useQuery hook\n */\nexport function useInfiniteModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: Omit<CreateInfiniteQueryOptions<R>, 'queryKey'>,\n fetch?: FetchFn\n) {\n return createInfiniteQuery<R>({\n queryKey: [QUERY_KEY_PREFIX + model, url, args],\n queryFn: ({ pageParam }) => fetcher<R, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a POST mutation with svelte-query.\n *\n * @param model The name of the model under mutation.\n * @param method The HTTP method.\n * @param modelMeta The model metadata.\n * @param url The request URL.\n * @param options The svelte-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n method: 'POST' | 'PUT' | 'DELETE',\n url: string,\n modelMeta: ModelMeta,\n options?: Omit<MutationOptions<Result, unknown, T>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) => {\n const reqUrl = method === 'DELETE' ? makeUrl(url, data) : url;\n const fetchInit: RequestInit = {\n method,\n ...(method !== 'DELETE' && {\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n }),\n };\n return fetcher<R, C>(reqUrl, fetchInit, fetch, checkReadBack) as Promise<Result>;\n };\n\n const finalOptions = { ...options, mutationFn };\n if (invalidateQueries) {\n const { logging } = getContext<APIContext>(SvelteQueryContextKey);\n const operation = url.split('/').pop();\n if (operation) {\n setupInvalidation(\n model,\n operation,\n modelMeta,\n finalOptions,\n (predicate) => queryClient.invalidateQueries({ predicate }),\n logging\n );\n }\n }\n\n return createMutation(finalOptions);\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { deserialize, serialize } from '@zenstackhq/runtime/browser';\nimport { getMutatedModels, getReadModels, type ModelMeta, type PrismaWriteActionType } from '@zenstackhq/runtime/cross';\nimport * as crossFetch from 'cross-fetch';\n\n/**\n * The default query endpoint.\n */\nexport const DEFAULT_QUERY_ENDPOINT = '/api/model';\n\n/**\n * Prefix for react-query keys.\n */\nexport const QUERY_KEY_PREFIX = 'zenstack';\n\n/**\n * Function signature for `fetch`.\n */\nexport type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;\n\n/**\n * Context type for configuring the hooks.\n */\nexport type APIContext = {\n /**\n * The endpoint to use for the queries.\n */\n endpoint?: string;\n\n /**\n * A custom fetch function for sending the HTTP requests.\n */\n fetch?: FetchFn;\n\n /**\n * If logging is enabled.\n */\n logging?: boolean;\n};\n\nexport async function fetcher<R, C extends boolean>(\n url: string,\n options?: RequestInit,\n fetch?: FetchFn,\n checkReadBack?: C\n): Promise<C extends true ? R | undefined : R> {\n const _fetch = fetch ?? crossFetch.fetch;\n const res = await _fetch(url, options);\n if (!res.ok) {\n const errData = unmarshal(await res.text());\n if (\n checkReadBack !== false &&\n errData.error?.prisma &&\n errData.error?.code === 'P2004' &&\n errData.error?.reason === 'RESULT_NOT_READABLE'\n ) {\n // policy doesn't allow mutation result to be read back, just return undefined\n return undefined as any;\n }\n const error: Error & { info?: unknown; status?: number } = new Error(\n 'An error occurred while fetching the data.'\n );\n error.info = errData.error;\n error.status = res.status;\n throw error;\n }\n\n const textResult = await res.text();\n try {\n return unmarshal(textResult).data as R;\n } catch (err) {\n console.error(`Unable to deserialize data:`, textResult);\n throw err;\n }\n}\n\ntype QueryKey = [string /* prefix */, string /* model */, string /* operation */, unknown /* args */];\n\n/**\n * Computes query key for the given model, operation and query args.\n * @param model Model name.\n * @param urlOrOperation Prisma operation (e.g, `findMany`) or request URL. If it's a URL, the last path segment will be used as the operation name.\n * @param args Prisma query arguments.\n * @returns Query key\n */\nexport function getQueryKey(model: string, urlOrOperation: string, args: unknown): QueryKey {\n if (!urlOrOperation) {\n throw new Error('Invalid urlOrOperation');\n }\n const operation = urlOrOperation.split('/').pop();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return [QUERY_KEY_PREFIX, model, operation!, args];\n}\n\nexport function marshal(value: unknown) {\n const { data, meta } = serialize(value);\n if (meta) {\n return JSON.stringify({ ...(data as any), meta: { serialization: meta } });\n } else {\n return JSON.stringify(data);\n }\n}\n\nexport function unmarshal(value: string) {\n const parsed = JSON.parse(value);\n if (parsed.data && parsed.meta?.serialization) {\n const deserializedData = deserialize(parsed.data, parsed.meta.serialization);\n return { ...parsed, data: deserializedData };\n } else {\n return parsed;\n }\n}\n\nexport function makeUrl(url: string, args: unknown) {\n if (!args) {\n return url;\n }\n\n const { data, meta } = serialize(args);\n let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`;\n if (meta) {\n result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`;\n }\n return result;\n}\n\ntype InvalidationPredicate = ({ queryKey }: { queryKey: readonly unknown[] }) => boolean;\n\n// sets up invalidation hook for a mutation\nexport function setupInvalidation(\n model: string,\n operation: string,\n modelMeta: ModelMeta,\n options: { onSuccess?: (...args: any[]) => any },\n invalidate: (predicate: InvalidationPredicate) => Promise<void>,\n logging = false\n) {\n const origOnSuccess = options?.onSuccess;\n options.onSuccess = async (...args: unknown[]) => {\n const [_, variables] = args;\n const predicate = await getInvalidationPredicate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n logging\n );\n await invalidate(predicate);\n return origOnSuccess?.(...args);\n };\n}\n\n// gets a predicate for evaluating whether a query should be invalidated\nasync function getInvalidationPredicate(\n model: string,\n operation: PrismaWriteActionType,\n mutationArgs: any,\n modelMeta: ModelMeta,\n logging = false\n) {\n const mutatedModels = await getMutatedModels(model, operation, mutationArgs, modelMeta);\n\n return ({ queryKey }: { queryKey: readonly unknown[] }) => {\n const [_model, queryModel, queryOp, args] = queryKey as QueryKey;\n\n if (mutatedModels.includes(queryModel)) {\n // direct match\n if (logging) {\n console.log(`Invalidating query [${queryKey}] due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n\n if (args) {\n // traverse query args to find nested reads that match the model under mutation\n if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {\n if (logging) {\n console.log(`Invalidating query [${queryKey}] due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n }\n\n return false;\n };\n}\n\n// find nested reads that match the given models\nfunction findNestedRead(visitingModel: string, targetModels: string[], modelMeta: ModelMeta, args: any) {\n const modelsRead = getReadModels(visitingModel, modelMeta, args);\n return targetModels.some((m) => modelsRead.includes(m));\n}\n"],"mappings":"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","names":["fetch","fetch"]}
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/svelte.ts","../../src/runtime/common.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n createInfiniteQuery,\n createMutation,\n createQuery,\n useQueryClient,\n type CreateInfiniteQueryOptions,\n type MutationOptions,\n type QueryOptions,\n} from '@tanstack/svelte-query';\nimport { ModelMeta } from '@zenstackhq/runtime/cross';\nimport { getContext, setContext } from 'svelte';\nimport {\n APIContext,\n DEFAULT_QUERY_ENDPOINT,\n FetchFn,\n fetcher,\n getQueryKey,\n makeUrl,\n marshal,\n setupInvalidation,\n setupOptimisticUpdate,\n} from './common';\n\nexport { APIContext as RequestHandlerContext } from './common';\n\n/**\n * Key for setting and getting the global query context.\n */\nexport const SvelteQueryContextKey = 'zenstack-svelte-query-context';\n\n/**\n * Set context for the generated TanStack Query hooks.\n */\nexport function setHooksContext(context: APIContext) {\n setContext(SvelteQueryContextKey, context);\n}\n\n/**\n * Hooks context.\n */\nexport function getHooksContext() {\n const { endpoint, ...rest } = getContext<APIContext>(SvelteQueryContextKey);\n return { endpoint: endpoint ?? DEFAULT_QUERY_ENDPOINT, ...rest };\n}\n\n/**\n * Creates a svelte-query query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The svelte-query options object\n * @param fetch The fetch function to use for sending the HTTP request\n * @param optimisticUpdate Whether to enable automatic optimistic update\n * @returns useQuery hook\n */\nexport function useModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: Omit<QueryOptions<R>, 'queryKey'>,\n fetch?: FetchFn,\n optimisticUpdate = false\n) {\n const reqUrl = makeUrl(url, args);\n return createQuery<R>({\n queryKey: getQueryKey(model, url, args, false, optimisticUpdate),\n queryFn: () => fetcher<R, false>(reqUrl, undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a svelte-query infinite query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The initial request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The svelte-query infinite query options object\n * @param fetch The fetch function to use for sending the HTTP request\n * @returns useQuery hook\n */\nexport function useInfiniteModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: Omit<CreateInfiniteQueryOptions<R>, 'queryKey'>,\n fetch?: FetchFn\n) {\n return createInfiniteQuery<R>({\n queryKey: getQueryKey(model, url, args, true),\n queryFn: ({ pageParam }) => fetcher<R, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a POST mutation with svelte-query.\n *\n * @param model The name of the model under mutation.\n * @param method The HTTP method.\n * @param modelMeta The model metadata.\n * @param url The request URL.\n * @param options The svelte-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @param checkReadBack Whether to check for read back errors and return undefined if found.\n * @param optimisticUpdate Whether to enable automatic optimistic update.\n * @returns useMutation hooks\n */\nexport function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n method: 'POST' | 'PUT' | 'DELETE',\n url: string,\n modelMeta: ModelMeta,\n options?: Omit<MutationOptions<Result, unknown, T>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C,\n optimisticUpdate = false\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) => {\n const reqUrl = method === 'DELETE' ? makeUrl(url, data) : url;\n const fetchInit: RequestInit = {\n method,\n ...(method !== 'DELETE' && {\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n }),\n };\n return fetcher<R, C>(reqUrl, fetchInit, fetch, checkReadBack) as Promise<Result>;\n };\n\n const finalOptions = { ...options, mutationFn };\n const operation = url.split('/').pop();\n if (operation) {\n const { logging } = getContext<APIContext>(SvelteQueryContextKey);\n\n if (invalidateQueries) {\n setupInvalidation(\n model,\n operation,\n modelMeta,\n finalOptions,\n (predicate) => queryClient.invalidateQueries({ predicate }),\n logging\n );\n }\n\n if (optimisticUpdate) {\n setupOptimisticUpdate(\n model,\n operation,\n modelMeta,\n finalOptions,\n queryClient.getQueryCache().getAll(),\n (queryKey, data) => queryClient.setQueryData<unknown>(queryKey, data),\n invalidateQueries ? (predicate) => queryClient.invalidateQueries({ predicate }) : undefined,\n logging\n );\n }\n }\n\n return createMutation(finalOptions);\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { deserialize, serialize } from '@zenstackhq/runtime/browser';\nimport {\n applyMutation,\n getMutatedModels,\n getReadModels,\n type ModelMeta,\n type PrismaWriteActionType,\n} from '@zenstackhq/runtime/cross';\nimport * as crossFetch from 'cross-fetch';\n\n/**\n * The default query endpoint.\n */\nexport const DEFAULT_QUERY_ENDPOINT = '/api/model';\n\n/**\n * Prefix for react-query keys.\n */\nexport const QUERY_KEY_PREFIX = 'zenstack';\n\n/**\n * Function signature for `fetch`.\n */\nexport type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;\n\n/**\n * Context type for configuring the hooks.\n */\nexport type APIContext = {\n /**\n * The endpoint to use for the queries.\n */\n endpoint?: string;\n\n /**\n * A custom fetch function for sending the HTTP requests.\n */\n fetch?: FetchFn;\n\n /**\n * If logging is enabled.\n */\n logging?: boolean;\n};\n\nexport async function fetcher<R, C extends boolean>(\n url: string,\n options?: RequestInit,\n fetch?: FetchFn,\n checkReadBack?: C\n): Promise<C extends true ? R | undefined : R> {\n const _fetch = fetch ?? crossFetch.fetch;\n const res = await _fetch(url, options);\n if (!res.ok) {\n const errData = unmarshal(await res.text());\n if (\n checkReadBack !== false &&\n errData.error?.prisma &&\n errData.error?.code === 'P2004' &&\n errData.error?.reason === 'RESULT_NOT_READABLE'\n ) {\n // policy doesn't allow mutation result to be read back, just return undefined\n return undefined as any;\n }\n const error: Error & { info?: unknown; status?: number } = new Error(\n 'An error occurred while fetching the data.'\n );\n error.info = errData.error;\n error.status = res.status;\n throw error;\n }\n\n const textResult = await res.text();\n try {\n return unmarshal(textResult).data as R;\n } catch (err) {\n console.error(`Unable to deserialize data:`, textResult);\n throw err;\n }\n}\n\ntype QueryKey = [\n string /* prefix */,\n string /* model */,\n string /* operation */,\n unknown /* args */,\n {\n infinite: boolean;\n optimisticUpdate: boolean;\n } /* flags */\n];\n\n/**\n * Computes query key for the given model, operation and query args.\n * @param model Model name.\n * @param urlOrOperation Prisma operation (e.g, `findMany`) or request URL. If it's a URL, the last path segment will be used as the operation name.\n * @param args Prisma query arguments.\n * @param infinite Whether the query is infinite.\n * @param optimisticUpdate Whether the query is optimistically updated.\n * @returns Query key\n */\nexport function getQueryKey(\n model: string,\n urlOrOperation: string,\n args: unknown,\n infinite = false,\n optimisticUpdate = false\n): QueryKey {\n if (!urlOrOperation) {\n throw new Error('Invalid urlOrOperation');\n }\n const operation = urlOrOperation.split('/').pop();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return [QUERY_KEY_PREFIX, model, operation!, args, { infinite, optimisticUpdate }];\n}\n\nexport function marshal(value: unknown) {\n const { data, meta } = serialize(value);\n if (meta) {\n return JSON.stringify({ ...(data as any), meta: { serialization: meta } });\n } else {\n return JSON.stringify(data);\n }\n}\n\nexport function unmarshal(value: string) {\n const parsed = JSON.parse(value);\n if (parsed.data && parsed.meta?.serialization) {\n const deserializedData = deserialize(parsed.data, parsed.meta.serialization);\n return { ...parsed, data: deserializedData };\n } else {\n return parsed;\n }\n}\n\nexport function makeUrl(url: string, args: unknown) {\n if (!args) {\n return url;\n }\n\n const { data, meta } = serialize(args);\n let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`;\n if (meta) {\n result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`;\n }\n return result;\n}\n\ntype InvalidationPredicate = ({ queryKey }: { queryKey: readonly unknown[] }) => boolean;\ntype InvalidateFunc = (predicate: InvalidationPredicate) => Promise<void>;\ntype MutationOptions = {\n onMutate?: (...args: any[]) => any;\n onSuccess?: (...args: any[]) => any;\n onSettled?: (...args: any[]) => any;\n};\n\n// sets up invalidation hook for a mutation\nexport function setupInvalidation(\n model: string,\n operation: string,\n modelMeta: ModelMeta,\n options: MutationOptions,\n invalidate: InvalidateFunc,\n logging = false\n) {\n const origOnSuccess = options?.onSuccess;\n options.onSuccess = async (...args: unknown[]) => {\n const [_, variables] = args;\n const predicate = await getInvalidationPredicate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n logging\n );\n await invalidate(predicate);\n return origOnSuccess?.(...args);\n };\n}\n\n// gets a predicate for evaluating whether a query should be invalidated\nasync function getInvalidationPredicate(\n model: string,\n operation: PrismaWriteActionType,\n mutationArgs: any,\n modelMeta: ModelMeta,\n logging = false\n) {\n const mutatedModels = await getMutatedModels(model, operation, mutationArgs, modelMeta);\n\n return ({ queryKey }: { queryKey: readonly unknown[] }) => {\n const [_, queryModel, , args] = queryKey as QueryKey;\n\n if (mutatedModels.includes(queryModel)) {\n // direct match\n if (logging) {\n console.log(`Invalidating query ${JSON.stringify(queryKey)} due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n\n if (args) {\n // traverse query args to find nested reads that match the model under mutation\n if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {\n if (logging) {\n console.log(\n `Invalidating query ${JSON.stringify(queryKey)} due to mutation \"${model}.${operation}\"`\n );\n }\n return true;\n }\n }\n\n return false;\n };\n}\n\n// find nested reads that match the given models\nfunction findNestedRead(visitingModel: string, targetModels: string[], modelMeta: ModelMeta, args: any) {\n const modelsRead = getReadModels(visitingModel, modelMeta, args);\n return targetModels.some((m) => modelsRead.includes(m));\n}\n\ntype QueryCache = {\n queryKey: readonly unknown[];\n state: {\n data: unknown;\n error: unknown;\n };\n}[];\n\ntype SetCacheFunc = (queryKey: readonly unknown[], data: unknown) => void;\n\nexport function setupOptimisticUpdate(\n model: string,\n operation: string,\n modelMeta: ModelMeta,\n options: MutationOptions,\n queryCache: QueryCache,\n setCache: SetCacheFunc,\n invalidate?: InvalidateFunc,\n logging = false\n) {\n const origOnMutate = options?.onMutate;\n const origOnSettled = options?.onSettled;\n\n options.onMutate = async (...args: unknown[]) => {\n const [variables] = args;\n await optimisticUpdate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n queryCache,\n setCache,\n logging\n );\n return origOnMutate?.(...args);\n };\n\n options.onSettled = async (...args: unknown[]) => {\n if (invalidate) {\n const [, , variables] = args;\n const predicate = await getInvalidationPredicate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n logging\n );\n await invalidate(predicate);\n }\n return origOnSettled?.(...args);\n };\n}\n\n// optimistically updates query cache\nasync function optimisticUpdate(\n mutationModel: string,\n mutationOp: string,\n mutationArgs: any,\n modelMeta: ModelMeta,\n queryCache: QueryCache,\n setCache: SetCacheFunc,\n logging = false\n) {\n for (const cacheItem of queryCache) {\n const {\n queryKey,\n state: { data, error },\n } = cacheItem;\n\n if (error) {\n continue;\n }\n\n const [_, queryModel, queryOp, _queryArgs, { optimisticUpdate }] = queryKey as QueryKey;\n if (!optimisticUpdate) {\n continue;\n }\n\n const mutatedData = await applyMutation(\n queryModel,\n queryOp,\n data,\n mutationModel,\n mutationOp as PrismaWriteActionType,\n mutationArgs,\n modelMeta,\n logging\n );\n\n if (mutatedData !== undefined) {\n // mutation applicable to this query, update cache\n if (logging) {\n console.log(\n `Optimistically updating query ${JSON.stringify(\n queryKey\n )} due to mutation \"${mutationModel}.${mutationOp}\"`\n );\n }\n setCache(queryKey, mutatedData);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAQO;AAEP,oBAAuC;;;ACTvC,qBAAuC;AACvC,mBAMO;AACP,iBAA4B;AAKrB,IAAM,yBAAyB;AAK/B,IAAM,mBAAmB;AA2BhC,SAAsB,QAClB,KACA,SACAA,QACA,eAC2C;AAAA;AApD/C;AAqDI,UAAM,SAASA,UAAA,OAAAA,SAAoB;AACnC,UAAM,MAAM,MAAM,OAAO,KAAK,OAAO;AACrC,QAAI,CAAC,IAAI,IAAI;AACT,YAAM,UAAU,UAAU,MAAM,IAAI,KAAK,CAAC;AAC1C,UACI,kBAAkB,WAClB,aAAQ,UAAR,mBAAe,aACf,aAAQ,UAAR,mBAAe,UAAS,aACxB,aAAQ,UAAR,mBAAe,YAAW,uBAC5B;AAEE,eAAO;AAAA,MACX;AACA,YAAM,QAAqD,IAAI;AAAA,QAC3D;AAAA,MACJ;AACA,YAAM,OAAO,QAAQ;AACrB,YAAM,SAAS,IAAI;AACnB,YAAM;AAAA,IACV;AAEA,UAAM,aAAa,MAAM,IAAI,KAAK;AAClC,QAAI;AACA,aAAO,UAAU,UAAU,EAAE;AAAA,IACjC,SAAS,KAAK;AACV,cAAQ,MAAM,+BAA+B,UAAU;AACvD,YAAM;AAAA,IACV;AAAA,EACJ;AAAA;AAsBO,SAAS,YACZ,OACA,gBACA,MACA,WAAW,OACXC,oBAAmB,OACX;AACR,MAAI,CAAC,gBAAgB;AACjB,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC5C;AACA,QAAM,YAAY,eAAe,MAAM,GAAG,EAAE,IAAI;AAEhD,SAAO,CAAC,kBAAkB,OAAO,WAAY,MAAM,EAAE,UAAU,kBAAAA,kBAAiB,CAAC;AACrF;AAEO,SAAS,QAAQ,OAAgB;AACpC,QAAM,EAAE,MAAM,KAAK,QAAI,0BAAU,KAAK;AACtC,MAAI,MAAM;AACN,WAAO,KAAK,UAAU,iCAAM,OAAN,EAAoB,MAAM,EAAE,eAAe,KAAK,EAAE,EAAC;AAAA,EAC7E,OAAO;AACH,WAAO,KAAK,UAAU,IAAI;AAAA,EAC9B;AACJ;AAEO,SAAS,UAAU,OAAe;AA/HzC;AAgII,QAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,MAAI,OAAO,UAAQ,YAAO,SAAP,mBAAa,gBAAe;AAC3C,UAAM,uBAAmB,4BAAY,OAAO,MAAM,OAAO,KAAK,aAAa;AAC3E,WAAO,iCAAK,SAAL,EAAa,MAAM,iBAAiB;AAAA,EAC/C,OAAO;AACH,WAAO;AAAA,EACX;AACJ;AAEO,SAAS,QAAQ,KAAa,MAAe;AAChD,MAAI,CAAC,MAAM;AACP,WAAO;AAAA,EACX;AAEA,QAAM,EAAE,MAAM,KAAK,QAAI,0BAAU,IAAI;AACrC,MAAI,SAAS,GAAG,GAAG,MAAM,mBAAmB,KAAK,UAAU,IAAI,CAAC,CAAC;AACjE,MAAI,MAAM;AACN,cAAU,SAAS,mBAAmB,KAAK,UAAU,EAAE,eAAe,KAAK,CAAC,CAAC,CAAC;AAAA,EAClF;AACA,SAAO;AACX;AAWO,SAAS,kBACZ,OACA,WACA,WACA,SACA,YACA,UAAU,OACZ;AACE,QAAM,gBAAgB,mCAAS;AAC/B,UAAQ,YAAY,IAAU,SAAoB;AAC9C,UAAM,CAAC,GAAG,SAAS,IAAI;AACvB,UAAM,YAAY,MAAM;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,WAAW,SAAS;AAC1B,WAAO,+CAAgB,GAAG;AAAA,EAC9B;AACJ;AAGA,SAAe,yBACX,OACA,WACA,cACA,WACA,UAAU,OACZ;AAAA;AACE,UAAM,gBAAgB,UAAM,+BAAiB,OAAO,WAAW,cAAc,SAAS;AAEtF,WAAO,CAAC,EAAE,SAAS,MAAwC;AACvD,YAAM,CAAC,GAAG,YAAY,EAAE,IAAI,IAAI;AAEhC,UAAI,cAAc,SAAS,UAAU,GAAG;AAEpC,YAAI,SAAS;AACT,kBAAQ,IAAI,sBAAsB,KAAK,UAAU,QAAQ,CAAC,qBAAqB,KAAK,IAAI,SAAS,GAAG;AAAA,QACxG;AACA,eAAO;AAAA,MACX;AAEA,UAAI,MAAM;AAEN,YAAI,eAAe,YAAY,eAAe,WAAW,IAAI,GAAG;AAC5D,cAAI,SAAS;AACT,oBAAQ;AAAA,cACJ,sBAAsB,KAAK,UAAU,QAAQ,CAAC,qBAAqB,KAAK,IAAI,SAAS;AAAA,YACzF;AAAA,UACJ;AACA,iBAAO;AAAA,QACX;AAAA,MACJ;AAEA,aAAO;AAAA,IACX;AAAA,EACJ;AAAA;AAGA,SAAS,eAAe,eAAuB,cAAwB,WAAsB,MAAW;AACpG,QAAM,iBAAa,4BAAc,eAAe,WAAW,IAAI;AAC/D,SAAO,aAAa,KAAK,CAAC,MAAM,WAAW,SAAS,CAAC,CAAC;AAC1D;AAYO,SAAS,sBACZ,OACA,WACA,WACA,SACA,YACA,UACA,YACA,UAAU,OACZ;AACE,QAAM,eAAe,mCAAS;AAC9B,QAAM,gBAAgB,mCAAS;AAE/B,UAAQ,WAAW,IAAU,SAAoB;AAC7C,UAAM,CAAC,SAAS,IAAI;AACpB,UAAM;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,WAAO,6CAAe,GAAG;AAAA,EAC7B;AAEA,UAAQ,YAAY,IAAU,SAAoB;AAC9C,QAAI,YAAY;AACZ,YAAM,CAAC,EAAE,EAAE,SAAS,IAAI;AACxB,YAAM,YAAY,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ;AACA,YAAM,WAAW,SAAS;AAAA,IAC9B;AACA,WAAO,+CAAgB,GAAG;AAAA,EAC9B;AACJ;AAGA,SAAe,iBACX,eACA,YACA,cACA,WACA,YACA,UACA,UAAU,OACZ;AAAA;AACE,eAAW,aAAa,YAAY;AAChC,YAAM;AAAA,QACF;AAAA,QACA,OAAO,EAAE,MAAM,MAAM;AAAA,MACzB,IAAI;AAEJ,UAAI,OAAO;AACP;AAAA,MACJ;AAEA,YAAM,CAAC,GAAG,YAAY,SAAS,YAAY,EAAE,kBAAAA,kBAAiB,CAAC,IAAI;AACnE,UAAI,CAACA,mBAAkB;AACnB;AAAA,MACJ;AAEA,YAAM,cAAc,UAAM;AAAA,QACtB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ;AAEA,UAAI,gBAAgB,QAAW;AAE3B,YAAI,SAAS;AACT,kBAAQ;AAAA,YACJ,iCAAiC,KAAK;AAAA,cAClC;AAAA,YACJ,CAAC,qBAAqB,aAAa,IAAI,UAAU;AAAA,UACrD;AAAA,QACJ;AACA,iBAAS,UAAU,WAAW;AAAA,MAClC;AAAA,IACJ;AAAA,EACJ;AAAA;;;ADzSO,IAAM,wBAAwB;AAK9B,SAAS,gBAAgB,SAAqB;AACjD,gCAAW,uBAAuB,OAAO;AAC7C;AAKO,SAAS,kBAAkB;AAC9B,QAA8B,mCAAuB,qBAAqB,GAAlE,WA1CZ,IA0CkC,IAAT,iBAAS,IAAT,CAAb;AACR,SAAO,iBAAE,UAAU,8BAAY,0BAA2B;AAC9D;AAaO,SAAS,cACZ,OACA,KACA,MACA,SACAC,QACAC,oBAAmB,OACrB;AACE,QAAM,SAAS,QAAQ,KAAK,IAAI;AAChC,aAAO,iCAAe;AAAA,IAClB,UAAU,YAAY,OAAO,KAAK,MAAM,OAAOA,iBAAgB;AAAA,IAC/D,SAAS,MAAM,QAAkB,QAAQ,QAAWD,QAAO,KAAK;AAAA,KAC7D,QACN;AACL;AAYO,SAAS,sBACZ,OACA,KACA,MACA,SACAA,QACF;AACE,aAAO,yCAAuB;AAAA,IAC1B,UAAU,YAAY,OAAO,KAAK,MAAM,IAAI;AAAA,IAC5C,SAAS,CAAC,EAAE,UAAU,MAAM,QAAkB,QAAQ,KAAK,gCAAa,IAAI,GAAG,QAAWA,QAAO,KAAK;AAAA,KACnG,QACN;AACL;AAeO,SAAS,iBACZ,OACA,QACA,KACA,WACA,SACAA,QACA,oBAAoB,MACpB,eACAC,oBAAmB,OACrB;AACE,QAAM,kBAAc,oCAAe;AACnC,QAAM,aAAa,CAAC,SAAc;AAC9B,UAAM,SAAS,WAAW,WAAW,QAAQ,KAAK,IAAI,IAAI;AAC1D,UAAM,YAAyB;AAAA,MAC3B;AAAA,OACI,WAAW,YAAY;AAAA,MACvB,SAAS;AAAA,QACL,gBAAgB;AAAA,MACpB;AAAA,MACA,MAAM,QAAQ,IAAI;AAAA,IACtB;AAEJ,WAAO,QAAc,QAAQ,WAAWD,QAAO,aAAa;AAAA,EAChE;AAEA,QAAM,eAAe,iCAAK,UAAL,EAAc,WAAW;AAC9C,QAAM,YAAY,IAAI,MAAM,GAAG,EAAE,IAAI;AACrC,MAAI,WAAW;AACX,UAAM,EAAE,QAAQ,QAAI,0BAAuB,qBAAqB;AAEhE,QAAI,mBAAmB;AACnB;AAAA,QACI;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,CAAC,cAAc,YAAY,kBAAkB,EAAE,UAAU,CAAC;AAAA,QAC1D;AAAA,MACJ;AAAA,IACJ;AAEA,QAAIC,mBAAkB;AAClB;AAAA,QACI;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,cAAc,EAAE,OAAO;AAAA,QACnC,CAAC,UAAU,SAAS,YAAY,aAAsB,UAAU,IAAI;AAAA,QACpE,oBAAoB,CAAC,cAAc,YAAY,kBAAkB,EAAE,UAAU,CAAC,IAAI;AAAA,QAClF;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAEA,aAAO,oCAAe,YAAY;AACtC;","names":["fetch","optimisticUpdate","fetch","optimisticUpdate"]}
|
package/runtime/svelte.mjs
CHANGED
|
@@ -61,7 +61,11 @@ import { getContext, setContext } from "svelte";
|
|
|
61
61
|
|
|
62
62
|
// src/runtime/common.ts
|
|
63
63
|
import { deserialize, serialize } from "@zenstackhq/runtime/browser";
|
|
64
|
-
import {
|
|
64
|
+
import {
|
|
65
|
+
applyMutation,
|
|
66
|
+
getMutatedModels,
|
|
67
|
+
getReadModels
|
|
68
|
+
} from "@zenstackhq/runtime/cross";
|
|
65
69
|
import * as crossFetch from "cross-fetch";
|
|
66
70
|
var DEFAULT_QUERY_ENDPOINT = "/api/model";
|
|
67
71
|
var QUERY_KEY_PREFIX = "zenstack";
|
|
@@ -91,6 +95,13 @@ function fetcher(url, options, fetch2, checkReadBack) {
|
|
|
91
95
|
}
|
|
92
96
|
});
|
|
93
97
|
}
|
|
98
|
+
function getQueryKey(model, urlOrOperation, args, infinite = false, optimisticUpdate2 = false) {
|
|
99
|
+
if (!urlOrOperation) {
|
|
100
|
+
throw new Error("Invalid urlOrOperation");
|
|
101
|
+
}
|
|
102
|
+
const operation = urlOrOperation.split("/").pop();
|
|
103
|
+
return [QUERY_KEY_PREFIX, model, operation, args, { infinite, optimisticUpdate: optimisticUpdate2 }];
|
|
104
|
+
}
|
|
94
105
|
function marshal(value) {
|
|
95
106
|
const { data, meta } = serialize(value);
|
|
96
107
|
if (meta) {
|
|
@@ -139,17 +150,19 @@ function getInvalidationPredicate(model, operation, mutationArgs, modelMeta, log
|
|
|
139
150
|
return __async(this, null, function* () {
|
|
140
151
|
const mutatedModels = yield getMutatedModels(model, operation, mutationArgs, modelMeta);
|
|
141
152
|
return ({ queryKey }) => {
|
|
142
|
-
const [
|
|
153
|
+
const [_, queryModel, , args] = queryKey;
|
|
143
154
|
if (mutatedModels.includes(queryModel)) {
|
|
144
155
|
if (logging) {
|
|
145
|
-
console.log(`Invalidating query
|
|
156
|
+
console.log(`Invalidating query ${JSON.stringify(queryKey)} due to mutation "${model}.${operation}"`);
|
|
146
157
|
}
|
|
147
158
|
return true;
|
|
148
159
|
}
|
|
149
160
|
if (args) {
|
|
150
161
|
if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {
|
|
151
162
|
if (logging) {
|
|
152
|
-
console.log(
|
|
163
|
+
console.log(
|
|
164
|
+
`Invalidating query ${JSON.stringify(queryKey)} due to mutation "${model}.${operation}"`
|
|
165
|
+
);
|
|
153
166
|
}
|
|
154
167
|
return true;
|
|
155
168
|
}
|
|
@@ -162,6 +175,74 @@ function findNestedRead(visitingModel, targetModels, modelMeta, args) {
|
|
|
162
175
|
const modelsRead = getReadModels(visitingModel, modelMeta, args);
|
|
163
176
|
return targetModels.some((m) => modelsRead.includes(m));
|
|
164
177
|
}
|
|
178
|
+
function setupOptimisticUpdate(model, operation, modelMeta, options, queryCache, setCache, invalidate, logging = false) {
|
|
179
|
+
const origOnMutate = options == null ? void 0 : options.onMutate;
|
|
180
|
+
const origOnSettled = options == null ? void 0 : options.onSettled;
|
|
181
|
+
options.onMutate = (...args) => __async(this, null, function* () {
|
|
182
|
+
const [variables] = args;
|
|
183
|
+
yield optimisticUpdate(
|
|
184
|
+
model,
|
|
185
|
+
operation,
|
|
186
|
+
variables,
|
|
187
|
+
modelMeta,
|
|
188
|
+
queryCache,
|
|
189
|
+
setCache,
|
|
190
|
+
logging
|
|
191
|
+
);
|
|
192
|
+
return origOnMutate == null ? void 0 : origOnMutate(...args);
|
|
193
|
+
});
|
|
194
|
+
options.onSettled = (...args) => __async(this, null, function* () {
|
|
195
|
+
if (invalidate) {
|
|
196
|
+
const [, , variables] = args;
|
|
197
|
+
const predicate = yield getInvalidationPredicate(
|
|
198
|
+
model,
|
|
199
|
+
operation,
|
|
200
|
+
variables,
|
|
201
|
+
modelMeta,
|
|
202
|
+
logging
|
|
203
|
+
);
|
|
204
|
+
yield invalidate(predicate);
|
|
205
|
+
}
|
|
206
|
+
return origOnSettled == null ? void 0 : origOnSettled(...args);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
function optimisticUpdate(mutationModel, mutationOp, mutationArgs, modelMeta, queryCache, setCache, logging = false) {
|
|
210
|
+
return __async(this, null, function* () {
|
|
211
|
+
for (const cacheItem of queryCache) {
|
|
212
|
+
const {
|
|
213
|
+
queryKey,
|
|
214
|
+
state: { data, error }
|
|
215
|
+
} = cacheItem;
|
|
216
|
+
if (error) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
const [_, queryModel, queryOp, _queryArgs, { optimisticUpdate: optimisticUpdate2 }] = queryKey;
|
|
220
|
+
if (!optimisticUpdate2) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
const mutatedData = yield applyMutation(
|
|
224
|
+
queryModel,
|
|
225
|
+
queryOp,
|
|
226
|
+
data,
|
|
227
|
+
mutationModel,
|
|
228
|
+
mutationOp,
|
|
229
|
+
mutationArgs,
|
|
230
|
+
modelMeta,
|
|
231
|
+
logging
|
|
232
|
+
);
|
|
233
|
+
if (mutatedData !== void 0) {
|
|
234
|
+
if (logging) {
|
|
235
|
+
console.log(
|
|
236
|
+
`Optimistically updating query ${JSON.stringify(
|
|
237
|
+
queryKey
|
|
238
|
+
)} due to mutation "${mutationModel}.${mutationOp}"`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
setCache(queryKey, mutatedData);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
165
246
|
|
|
166
247
|
// src/runtime/svelte.ts
|
|
167
248
|
var SvelteQueryContextKey = "zenstack-svelte-query-context";
|
|
@@ -172,20 +253,20 @@ function getHooksContext() {
|
|
|
172
253
|
const _a = getContext(SvelteQueryContextKey), { endpoint } = _a, rest = __objRest(_a, ["endpoint"]);
|
|
173
254
|
return __spreadValues({ endpoint: endpoint != null ? endpoint : DEFAULT_QUERY_ENDPOINT }, rest);
|
|
174
255
|
}
|
|
175
|
-
function useModelQuery(model, url, args, options, fetch2) {
|
|
256
|
+
function useModelQuery(model, url, args, options, fetch2, optimisticUpdate2 = false) {
|
|
176
257
|
const reqUrl = makeUrl(url, args);
|
|
177
258
|
return createQuery(__spreadValues({
|
|
178
|
-
queryKey:
|
|
259
|
+
queryKey: getQueryKey(model, url, args, false, optimisticUpdate2),
|
|
179
260
|
queryFn: () => fetcher(reqUrl, void 0, fetch2, false)
|
|
180
261
|
}, options));
|
|
181
262
|
}
|
|
182
263
|
function useInfiniteModelQuery(model, url, args, options, fetch2) {
|
|
183
264
|
return createInfiniteQuery(__spreadValues({
|
|
184
|
-
queryKey:
|
|
265
|
+
queryKey: getQueryKey(model, url, args, true),
|
|
185
266
|
queryFn: ({ pageParam }) => fetcher(makeUrl(url, pageParam != null ? pageParam : args), void 0, fetch2, false)
|
|
186
267
|
}, options));
|
|
187
268
|
}
|
|
188
|
-
function useModelMutation(model, method, url, modelMeta, options, fetch2, invalidateQueries = true, checkReadBack) {
|
|
269
|
+
function useModelMutation(model, method, url, modelMeta, options, fetch2, invalidateQueries = true, checkReadBack, optimisticUpdate2 = false) {
|
|
189
270
|
const queryClient = useQueryClient();
|
|
190
271
|
const mutationFn = (data) => {
|
|
191
272
|
const reqUrl = method === "DELETE" ? makeUrl(url, data) : url;
|
|
@@ -200,10 +281,10 @@ function useModelMutation(model, method, url, modelMeta, options, fetch2, invali
|
|
|
200
281
|
return fetcher(reqUrl, fetchInit, fetch2, checkReadBack);
|
|
201
282
|
};
|
|
202
283
|
const finalOptions = __spreadProps(__spreadValues({}, options), { mutationFn });
|
|
203
|
-
|
|
284
|
+
const operation = url.split("/").pop();
|
|
285
|
+
if (operation) {
|
|
204
286
|
const { logging } = getContext(SvelteQueryContextKey);
|
|
205
|
-
|
|
206
|
-
if (operation) {
|
|
287
|
+
if (invalidateQueries) {
|
|
207
288
|
setupInvalidation(
|
|
208
289
|
model,
|
|
209
290
|
operation,
|
|
@@ -213,6 +294,18 @@ function useModelMutation(model, method, url, modelMeta, options, fetch2, invali
|
|
|
213
294
|
logging
|
|
214
295
|
);
|
|
215
296
|
}
|
|
297
|
+
if (optimisticUpdate2) {
|
|
298
|
+
setupOptimisticUpdate(
|
|
299
|
+
model,
|
|
300
|
+
operation,
|
|
301
|
+
modelMeta,
|
|
302
|
+
finalOptions,
|
|
303
|
+
queryClient.getQueryCache().getAll(),
|
|
304
|
+
(queryKey, data) => queryClient.setQueryData(queryKey, data),
|
|
305
|
+
invalidateQueries ? (predicate) => queryClient.invalidateQueries({ predicate }) : void 0,
|
|
306
|
+
logging
|
|
307
|
+
);
|
|
308
|
+
}
|
|
216
309
|
}
|
|
217
310
|
return createMutation(finalOptions);
|
|
218
311
|
}
|
package/runtime/svelte.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/svelte.ts","../../src/runtime/common.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n createInfiniteQuery,\n createMutation,\n createQuery,\n useQueryClient,\n type CreateInfiniteQueryOptions,\n type MutationOptions,\n type QueryOptions,\n} from '@tanstack/svelte-query';\nimport { ModelMeta } from '@zenstackhq/runtime/cross';\nimport { getContext, setContext } from 'svelte';\nimport {\n APIContext,\n DEFAULT_QUERY_ENDPOINT,\n FetchFn,\n QUERY_KEY_PREFIX,\n fetcher,\n makeUrl,\n marshal,\n setupInvalidation,\n} from './common';\n\nexport { APIContext as RequestHandlerContext } from './common';\n\n/**\n * Key for setting and getting the global query context.\n */\nexport const SvelteQueryContextKey = 'zenstack-svelte-query-context';\n\n/**\n * Set context for the generated TanStack Query hooks.\n */\nexport function setHooksContext(context: APIContext) {\n setContext(SvelteQueryContextKey, context);\n}\n\n/**\n * Hooks context.\n */\nexport function getHooksContext() {\n const { endpoint, ...rest } = getContext<APIContext>(SvelteQueryContextKey);\n return { endpoint: endpoint ?? DEFAULT_QUERY_ENDPOINT, ...rest };\n}\n\n/**\n * Creates a svelte-query query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The svelte-query options object\n * @returns useQuery hook\n */\nexport function useModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: Omit<QueryOptions<R>, 'queryKey'>,\n fetch?: FetchFn\n) {\n const reqUrl = makeUrl(url, args);\n return createQuery<R>({\n queryKey: [QUERY_KEY_PREFIX + model, url, args],\n queryFn: () => fetcher<R, false>(reqUrl, undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a svelte-query infinite query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The initial request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The svelte-query infinite query options object\n * @returns useQuery hook\n */\nexport function useInfiniteModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: Omit<CreateInfiniteQueryOptions<R>, 'queryKey'>,\n fetch?: FetchFn\n) {\n return createInfiniteQuery<R>({\n queryKey: [QUERY_KEY_PREFIX + model, url, args],\n queryFn: ({ pageParam }) => fetcher<R, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a POST mutation with svelte-query.\n *\n * @param model The name of the model under mutation.\n * @param method The HTTP method.\n * @param modelMeta The model metadata.\n * @param url The request URL.\n * @param options The svelte-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @returns useMutation hooks\n */\nexport function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n method: 'POST' | 'PUT' | 'DELETE',\n url: string,\n modelMeta: ModelMeta,\n options?: Omit<MutationOptions<Result, unknown, T>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) => {\n const reqUrl = method === 'DELETE' ? makeUrl(url, data) : url;\n const fetchInit: RequestInit = {\n method,\n ...(method !== 'DELETE' && {\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n }),\n };\n return fetcher<R, C>(reqUrl, fetchInit, fetch, checkReadBack) as Promise<Result>;\n };\n\n const finalOptions = { ...options, mutationFn };\n if (invalidateQueries) {\n const { logging } = getContext<APIContext>(SvelteQueryContextKey);\n const operation = url.split('/').pop();\n if (operation) {\n setupInvalidation(\n model,\n operation,\n modelMeta,\n finalOptions,\n (predicate) => queryClient.invalidateQueries({ predicate }),\n logging\n );\n }\n }\n\n return createMutation(finalOptions);\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { deserialize, serialize } from '@zenstackhq/runtime/browser';\nimport { getMutatedModels, getReadModels, type ModelMeta, type PrismaWriteActionType } from '@zenstackhq/runtime/cross';\nimport * as crossFetch from 'cross-fetch';\n\n/**\n * The default query endpoint.\n */\nexport const DEFAULT_QUERY_ENDPOINT = '/api/model';\n\n/**\n * Prefix for react-query keys.\n */\nexport const QUERY_KEY_PREFIX = 'zenstack';\n\n/**\n * Function signature for `fetch`.\n */\nexport type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;\n\n/**\n * Context type for configuring the hooks.\n */\nexport type APIContext = {\n /**\n * The endpoint to use for the queries.\n */\n endpoint?: string;\n\n /**\n * A custom fetch function for sending the HTTP requests.\n */\n fetch?: FetchFn;\n\n /**\n * If logging is enabled.\n */\n logging?: boolean;\n};\n\nexport async function fetcher<R, C extends boolean>(\n url: string,\n options?: RequestInit,\n fetch?: FetchFn,\n checkReadBack?: C\n): Promise<C extends true ? R | undefined : R> {\n const _fetch = fetch ?? crossFetch.fetch;\n const res = await _fetch(url, options);\n if (!res.ok) {\n const errData = unmarshal(await res.text());\n if (\n checkReadBack !== false &&\n errData.error?.prisma &&\n errData.error?.code === 'P2004' &&\n errData.error?.reason === 'RESULT_NOT_READABLE'\n ) {\n // policy doesn't allow mutation result to be read back, just return undefined\n return undefined as any;\n }\n const error: Error & { info?: unknown; status?: number } = new Error(\n 'An error occurred while fetching the data.'\n );\n error.info = errData.error;\n error.status = res.status;\n throw error;\n }\n\n const textResult = await res.text();\n try {\n return unmarshal(textResult).data as R;\n } catch (err) {\n console.error(`Unable to deserialize data:`, textResult);\n throw err;\n }\n}\n\ntype QueryKey = [string /* prefix */, string /* model */, string /* operation */, unknown /* args */];\n\n/**\n * Computes query key for the given model, operation and query args.\n * @param model Model name.\n * @param urlOrOperation Prisma operation (e.g, `findMany`) or request URL. If it's a URL, the last path segment will be used as the operation name.\n * @param args Prisma query arguments.\n * @returns Query key\n */\nexport function getQueryKey(model: string, urlOrOperation: string, args: unknown): QueryKey {\n if (!urlOrOperation) {\n throw new Error('Invalid urlOrOperation');\n }\n const operation = urlOrOperation.split('/').pop();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return [QUERY_KEY_PREFIX, model, operation!, args];\n}\n\nexport function marshal(value: unknown) {\n const { data, meta } = serialize(value);\n if (meta) {\n return JSON.stringify({ ...(data as any), meta: { serialization: meta } });\n } else {\n return JSON.stringify(data);\n }\n}\n\nexport function unmarshal(value: string) {\n const parsed = JSON.parse(value);\n if (parsed.data && parsed.meta?.serialization) {\n const deserializedData = deserialize(parsed.data, parsed.meta.serialization);\n return { ...parsed, data: deserializedData };\n } else {\n return parsed;\n }\n}\n\nexport function makeUrl(url: string, args: unknown) {\n if (!args) {\n return url;\n }\n\n const { data, meta } = serialize(args);\n let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`;\n if (meta) {\n result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`;\n }\n return result;\n}\n\ntype InvalidationPredicate = ({ queryKey }: { queryKey: readonly unknown[] }) => boolean;\n\n// sets up invalidation hook for a mutation\nexport function setupInvalidation(\n model: string,\n operation: string,\n modelMeta: ModelMeta,\n options: { onSuccess?: (...args: any[]) => any },\n invalidate: (predicate: InvalidationPredicate) => Promise<void>,\n logging = false\n) {\n const origOnSuccess = options?.onSuccess;\n options.onSuccess = async (...args: unknown[]) => {\n const [_, variables] = args;\n const predicate = await getInvalidationPredicate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n logging\n );\n await invalidate(predicate);\n return origOnSuccess?.(...args);\n };\n}\n\n// gets a predicate for evaluating whether a query should be invalidated\nasync function getInvalidationPredicate(\n model: string,\n operation: PrismaWriteActionType,\n mutationArgs: any,\n modelMeta: ModelMeta,\n logging = false\n) {\n const mutatedModels = await getMutatedModels(model, operation, mutationArgs, modelMeta);\n\n return ({ queryKey }: { queryKey: readonly unknown[] }) => {\n const [_model, queryModel, queryOp, args] = queryKey as QueryKey;\n\n if (mutatedModels.includes(queryModel)) {\n // direct match\n if (logging) {\n console.log(`Invalidating query [${queryKey}] due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n\n if (args) {\n // traverse query args to find nested reads that match the model under mutation\n if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {\n if (logging) {\n console.log(`Invalidating query [${queryKey}] due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n }\n\n return false;\n };\n}\n\n// find nested reads that match the given models\nfunction findNestedRead(visitingModel: string, targetModels: string[], modelMeta: ModelMeta, args: any) {\n const modelsRead = getReadModels(visitingModel, modelMeta, args);\n return targetModels.some((m) => modelsRead.includes(m));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIG;AAEP,SAAS,YAAY,kBAAkB;;;ACTvC,SAAS,aAAa,iBAAiB;AACvC,SAAS,kBAAkB,qBAAiE;AAC5F,YAAY,gBAAgB;AAKrB,IAAM,yBAAyB;AAK/B,IAAM,mBAAmB;AA2BhC,SAAsB,QAClB,KACA,SACAA,QACA,eAC2C;AAAA;AA9C/C;AA+CI,UAAM,SAASA,UAAA,OAAAA,SAAoB;AACnC,UAAM,MAAM,MAAM,OAAO,KAAK,OAAO;AACrC,QAAI,CAAC,IAAI,IAAI;AACT,YAAM,UAAU,UAAU,MAAM,IAAI,KAAK,CAAC;AAC1C,UACI,kBAAkB,WAClB,aAAQ,UAAR,mBAAe,aACf,aAAQ,UAAR,mBAAe,UAAS,aACxB,aAAQ,UAAR,mBAAe,YAAW,uBAC5B;AAEE,eAAO;AAAA,MACX;AACA,YAAM,QAAqD,IAAI;AAAA,QAC3D;AAAA,MACJ;AACA,YAAM,OAAO,QAAQ;AACrB,YAAM,SAAS,IAAI;AACnB,YAAM;AAAA,IACV;AAEA,UAAM,aAAa,MAAM,IAAI,KAAK;AAClC,QAAI;AACA,aAAO,UAAU,UAAU,EAAE;AAAA,IACjC,SAAS,KAAK;AACV,cAAQ,MAAM,+BAA+B,UAAU;AACvD,YAAM;AAAA,IACV;AAAA,EACJ;AAAA;AAoBO,SAAS,QAAQ,OAAgB;AACpC,QAAM,EAAE,MAAM,KAAK,IAAI,UAAU,KAAK;AACtC,MAAI,MAAM;AACN,WAAO,KAAK,UAAU,iCAAM,OAAN,EAAoB,MAAM,EAAE,eAAe,KAAK,EAAE,EAAC;AAAA,EAC7E,OAAO;AACH,WAAO,KAAK,UAAU,IAAI;AAAA,EAC9B;AACJ;AAEO,SAAS,UAAU,OAAe;AAxGzC;AAyGI,QAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,MAAI,OAAO,UAAQ,YAAO,SAAP,mBAAa,gBAAe;AAC3C,UAAM,mBAAmB,YAAY,OAAO,MAAM,OAAO,KAAK,aAAa;AAC3E,WAAO,iCAAK,SAAL,EAAa,MAAM,iBAAiB;AAAA,EAC/C,OAAO;AACH,WAAO;AAAA,EACX;AACJ;AAEO,SAAS,QAAQ,KAAa,MAAe;AAChD,MAAI,CAAC,MAAM;AACP,WAAO;AAAA,EACX;AAEA,QAAM,EAAE,MAAM,KAAK,IAAI,UAAU,IAAI;AACrC,MAAI,SAAS,GAAG,GAAG,MAAM,mBAAmB,KAAK,UAAU,IAAI,CAAC,CAAC;AACjE,MAAI,MAAM;AACN,cAAU,SAAS,mBAAmB,KAAK,UAAU,EAAE,eAAe,KAAK,CAAC,CAAC,CAAC;AAAA,EAClF;AACA,SAAO;AACX;AAKO,SAAS,kBACZ,OACA,WACA,WACA,SACA,YACA,UAAU,OACZ;AACE,QAAM,gBAAgB,mCAAS;AAC/B,UAAQ,YAAY,IAAU,SAAoB;AAC9C,UAAM,CAAC,GAAG,SAAS,IAAI;AACvB,UAAM,YAAY,MAAM;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AACA,UAAM,WAAW,SAAS;AAC1B,WAAO,+CAAgB,GAAG;AAAA,EAC9B;AACJ;AAGA,SAAe,yBACX,OACA,WACA,cACA,WACA,UAAU,OACZ;AAAA;AACE,UAAM,gBAAgB,MAAM,iBAAiB,OAAO,WAAW,cAAc,SAAS;AAEtF,WAAO,CAAC,EAAE,SAAS,MAAwC;AACvD,YAAM,CAAC,QAAQ,YAAY,SAAS,IAAI,IAAI;AAE5C,UAAI,cAAc,SAAS,UAAU,GAAG;AAEpC,YAAI,SAAS;AACT,kBAAQ,IAAI,uBAAuB,QAAQ,sBAAsB,KAAK,IAAI,SAAS,GAAG;AAAA,QAC1F;AACA,eAAO;AAAA,MACX;AAEA,UAAI,MAAM;AAEN,YAAI,eAAe,YAAY,eAAe,WAAW,IAAI,GAAG;AAC5D,cAAI,SAAS;AACT,oBAAQ,IAAI,uBAAuB,QAAQ,sBAAsB,KAAK,IAAI,SAAS,GAAG;AAAA,UAC1F;AACA,iBAAO;AAAA,QACX;AAAA,MACJ;AAEA,aAAO;AAAA,IACX;AAAA,EACJ;AAAA;AAGA,SAAS,eAAe,eAAuB,cAAwB,WAAsB,MAAW;AACpG,QAAM,aAAa,cAAc,eAAe,WAAW,IAAI;AAC/D,SAAO,aAAa,KAAK,CAAC,MAAM,WAAW,SAAS,CAAC,CAAC;AAC1D;;;ADpKO,IAAM,wBAAwB;AAK9B,SAAS,gBAAgB,SAAqB;AACjD,aAAW,uBAAuB,OAAO;AAC7C;AAKO,SAAS,kBAAkB;AAC9B,QAA8B,gBAAuB,qBAAqB,GAAlE,WAzCZ,IAyCkC,IAAT,iBAAS,IAAT,CAAb;AACR,SAAO,iBAAE,UAAU,8BAAY,0BAA2B;AAC9D;AAWO,SAAS,cACZ,OACA,KACA,MACA,SACAC,QACF;AACE,QAAM,SAAS,QAAQ,KAAK,IAAI;AAChC,SAAO,YAAe;AAAA,IAClB,UAAU,CAAC,mBAAmB,OAAO,KAAK,IAAI;AAAA,IAC9C,SAAS,MAAM,QAAkB,QAAQ,QAAWA,QAAO,KAAK;AAAA,KAC7D,QACN;AACL;AAWO,SAAS,sBACZ,OACA,KACA,MACA,SACAA,QACF;AACE,SAAO,oBAAuB;AAAA,IAC1B,UAAU,CAAC,mBAAmB,OAAO,KAAK,IAAI;AAAA,IAC9C,SAAS,CAAC,EAAE,UAAU,MAAM,QAAkB,QAAQ,KAAK,gCAAa,IAAI,GAAG,QAAWA,QAAO,KAAK;AAAA,KACnG,QACN;AACL;AAaO,SAAS,iBACZ,OACA,QACA,KACA,WACA,SACAA,QACA,oBAAoB,MACpB,eACF;AACE,QAAM,cAAc,eAAe;AACnC,QAAM,aAAa,CAAC,SAAc;AAC9B,UAAM,SAAS,WAAW,WAAW,QAAQ,KAAK,IAAI,IAAI;AAC1D,UAAM,YAAyB;AAAA,MAC3B;AAAA,OACI,WAAW,YAAY;AAAA,MACvB,SAAS;AAAA,QACL,gBAAgB;AAAA,MACpB;AAAA,MACA,MAAM,QAAQ,IAAI;AAAA,IACtB;AAEJ,WAAO,QAAc,QAAQ,WAAWA,QAAO,aAAa;AAAA,EAChE;AAEA,QAAM,eAAe,iCAAK,UAAL,EAAc,WAAW;AAC9C,MAAI,mBAAmB;AACnB,UAAM,EAAE,QAAQ,IAAI,WAAuB,qBAAqB;AAChE,UAAM,YAAY,IAAI,MAAM,GAAG,EAAE,IAAI;AACrC,QAAI,WAAW;AACX;AAAA,QACI;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,CAAC,cAAc,YAAY,kBAAkB,EAAE,UAAU,CAAC;AAAA,QAC1D;AAAA,MACJ;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO,eAAe,YAAY;AACtC;","names":["fetch","fetch"]}
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/svelte.ts","../../src/runtime/common.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {\n createInfiniteQuery,\n createMutation,\n createQuery,\n useQueryClient,\n type CreateInfiniteQueryOptions,\n type MutationOptions,\n type QueryOptions,\n} from '@tanstack/svelte-query';\nimport { ModelMeta } from '@zenstackhq/runtime/cross';\nimport { getContext, setContext } from 'svelte';\nimport {\n APIContext,\n DEFAULT_QUERY_ENDPOINT,\n FetchFn,\n fetcher,\n getQueryKey,\n makeUrl,\n marshal,\n setupInvalidation,\n setupOptimisticUpdate,\n} from './common';\n\nexport { APIContext as RequestHandlerContext } from './common';\n\n/**\n * Key for setting and getting the global query context.\n */\nexport const SvelteQueryContextKey = 'zenstack-svelte-query-context';\n\n/**\n * Set context for the generated TanStack Query hooks.\n */\nexport function setHooksContext(context: APIContext) {\n setContext(SvelteQueryContextKey, context);\n}\n\n/**\n * Hooks context.\n */\nexport function getHooksContext() {\n const { endpoint, ...rest } = getContext<APIContext>(SvelteQueryContextKey);\n return { endpoint: endpoint ?? DEFAULT_QUERY_ENDPOINT, ...rest };\n}\n\n/**\n * Creates a svelte-query query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The svelte-query options object\n * @param fetch The fetch function to use for sending the HTTP request\n * @param optimisticUpdate Whether to enable automatic optimistic update\n * @returns useQuery hook\n */\nexport function useModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: Omit<QueryOptions<R>, 'queryKey'>,\n fetch?: FetchFn,\n optimisticUpdate = false\n) {\n const reqUrl = makeUrl(url, args);\n return createQuery<R>({\n queryKey: getQueryKey(model, url, args, false, optimisticUpdate),\n queryFn: () => fetcher<R, false>(reqUrl, undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a svelte-query infinite query.\n *\n * @param model The name of the model under query.\n * @param url The request URL.\n * @param args The initial request args object, URL-encoded and appended as \"?q=\" parameter\n * @param options The svelte-query infinite query options object\n * @param fetch The fetch function to use for sending the HTTP request\n * @returns useQuery hook\n */\nexport function useInfiniteModelQuery<R>(\n model: string,\n url: string,\n args?: unknown,\n options?: Omit<CreateInfiniteQueryOptions<R>, 'queryKey'>,\n fetch?: FetchFn\n) {\n return createInfiniteQuery<R>({\n queryKey: getQueryKey(model, url, args, true),\n queryFn: ({ pageParam }) => fetcher<R, false>(makeUrl(url, pageParam ?? args), undefined, fetch, false),\n ...options,\n });\n}\n\n/**\n * Creates a POST mutation with svelte-query.\n *\n * @param model The name of the model under mutation.\n * @param method The HTTP method.\n * @param modelMeta The model metadata.\n * @param url The request URL.\n * @param options The svelte-query options.\n * @param invalidateQueries Whether to invalidate queries after mutation.\n * @param checkReadBack Whether to check for read back errors and return undefined if found.\n * @param optimisticUpdate Whether to enable automatic optimistic update.\n * @returns useMutation hooks\n */\nexport function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(\n model: string,\n method: 'POST' | 'PUT' | 'DELETE',\n url: string,\n modelMeta: ModelMeta,\n options?: Omit<MutationOptions<Result, unknown, T>, 'mutationFn'>,\n fetch?: FetchFn,\n invalidateQueries = true,\n checkReadBack?: C,\n optimisticUpdate = false\n) {\n const queryClient = useQueryClient();\n const mutationFn = (data: any) => {\n const reqUrl = method === 'DELETE' ? makeUrl(url, data) : url;\n const fetchInit: RequestInit = {\n method,\n ...(method !== 'DELETE' && {\n headers: {\n 'content-type': 'application/json',\n },\n body: marshal(data),\n }),\n };\n return fetcher<R, C>(reqUrl, fetchInit, fetch, checkReadBack) as Promise<Result>;\n };\n\n const finalOptions = { ...options, mutationFn };\n const operation = url.split('/').pop();\n if (operation) {\n const { logging } = getContext<APIContext>(SvelteQueryContextKey);\n\n if (invalidateQueries) {\n setupInvalidation(\n model,\n operation,\n modelMeta,\n finalOptions,\n (predicate) => queryClient.invalidateQueries({ predicate }),\n logging\n );\n }\n\n if (optimisticUpdate) {\n setupOptimisticUpdate(\n model,\n operation,\n modelMeta,\n finalOptions,\n queryClient.getQueryCache().getAll(),\n (queryKey, data) => queryClient.setQueryData<unknown>(queryKey, data),\n invalidateQueries ? (predicate) => queryClient.invalidateQueries({ predicate }) : undefined,\n logging\n );\n }\n }\n\n return createMutation(finalOptions);\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { deserialize, serialize } from '@zenstackhq/runtime/browser';\nimport {\n applyMutation,\n getMutatedModels,\n getReadModels,\n type ModelMeta,\n type PrismaWriteActionType,\n} from '@zenstackhq/runtime/cross';\nimport * as crossFetch from 'cross-fetch';\n\n/**\n * The default query endpoint.\n */\nexport const DEFAULT_QUERY_ENDPOINT = '/api/model';\n\n/**\n * Prefix for react-query keys.\n */\nexport const QUERY_KEY_PREFIX = 'zenstack';\n\n/**\n * Function signature for `fetch`.\n */\nexport type FetchFn = (url: string, options?: RequestInit) => Promise<Response>;\n\n/**\n * Context type for configuring the hooks.\n */\nexport type APIContext = {\n /**\n * The endpoint to use for the queries.\n */\n endpoint?: string;\n\n /**\n * A custom fetch function for sending the HTTP requests.\n */\n fetch?: FetchFn;\n\n /**\n * If logging is enabled.\n */\n logging?: boolean;\n};\n\nexport async function fetcher<R, C extends boolean>(\n url: string,\n options?: RequestInit,\n fetch?: FetchFn,\n checkReadBack?: C\n): Promise<C extends true ? R | undefined : R> {\n const _fetch = fetch ?? crossFetch.fetch;\n const res = await _fetch(url, options);\n if (!res.ok) {\n const errData = unmarshal(await res.text());\n if (\n checkReadBack !== false &&\n errData.error?.prisma &&\n errData.error?.code === 'P2004' &&\n errData.error?.reason === 'RESULT_NOT_READABLE'\n ) {\n // policy doesn't allow mutation result to be read back, just return undefined\n return undefined as any;\n }\n const error: Error & { info?: unknown; status?: number } = new Error(\n 'An error occurred while fetching the data.'\n );\n error.info = errData.error;\n error.status = res.status;\n throw error;\n }\n\n const textResult = await res.text();\n try {\n return unmarshal(textResult).data as R;\n } catch (err) {\n console.error(`Unable to deserialize data:`, textResult);\n throw err;\n }\n}\n\ntype QueryKey = [\n string /* prefix */,\n string /* model */,\n string /* operation */,\n unknown /* args */,\n {\n infinite: boolean;\n optimisticUpdate: boolean;\n } /* flags */\n];\n\n/**\n * Computes query key for the given model, operation and query args.\n * @param model Model name.\n * @param urlOrOperation Prisma operation (e.g, `findMany`) or request URL. If it's a URL, the last path segment will be used as the operation name.\n * @param args Prisma query arguments.\n * @param infinite Whether the query is infinite.\n * @param optimisticUpdate Whether the query is optimistically updated.\n * @returns Query key\n */\nexport function getQueryKey(\n model: string,\n urlOrOperation: string,\n args: unknown,\n infinite = false,\n optimisticUpdate = false\n): QueryKey {\n if (!urlOrOperation) {\n throw new Error('Invalid urlOrOperation');\n }\n const operation = urlOrOperation.split('/').pop();\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n return [QUERY_KEY_PREFIX, model, operation!, args, { infinite, optimisticUpdate }];\n}\n\nexport function marshal(value: unknown) {\n const { data, meta } = serialize(value);\n if (meta) {\n return JSON.stringify({ ...(data as any), meta: { serialization: meta } });\n } else {\n return JSON.stringify(data);\n }\n}\n\nexport function unmarshal(value: string) {\n const parsed = JSON.parse(value);\n if (parsed.data && parsed.meta?.serialization) {\n const deserializedData = deserialize(parsed.data, parsed.meta.serialization);\n return { ...parsed, data: deserializedData };\n } else {\n return parsed;\n }\n}\n\nexport function makeUrl(url: string, args: unknown) {\n if (!args) {\n return url;\n }\n\n const { data, meta } = serialize(args);\n let result = `${url}?q=${encodeURIComponent(JSON.stringify(data))}`;\n if (meta) {\n result += `&meta=${encodeURIComponent(JSON.stringify({ serialization: meta }))}`;\n }\n return result;\n}\n\ntype InvalidationPredicate = ({ queryKey }: { queryKey: readonly unknown[] }) => boolean;\ntype InvalidateFunc = (predicate: InvalidationPredicate) => Promise<void>;\ntype MutationOptions = {\n onMutate?: (...args: any[]) => any;\n onSuccess?: (...args: any[]) => any;\n onSettled?: (...args: any[]) => any;\n};\n\n// sets up invalidation hook for a mutation\nexport function setupInvalidation(\n model: string,\n operation: string,\n modelMeta: ModelMeta,\n options: MutationOptions,\n invalidate: InvalidateFunc,\n logging = false\n) {\n const origOnSuccess = options?.onSuccess;\n options.onSuccess = async (...args: unknown[]) => {\n const [_, variables] = args;\n const predicate = await getInvalidationPredicate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n logging\n );\n await invalidate(predicate);\n return origOnSuccess?.(...args);\n };\n}\n\n// gets a predicate for evaluating whether a query should be invalidated\nasync function getInvalidationPredicate(\n model: string,\n operation: PrismaWriteActionType,\n mutationArgs: any,\n modelMeta: ModelMeta,\n logging = false\n) {\n const mutatedModels = await getMutatedModels(model, operation, mutationArgs, modelMeta);\n\n return ({ queryKey }: { queryKey: readonly unknown[] }) => {\n const [_, queryModel, , args] = queryKey as QueryKey;\n\n if (mutatedModels.includes(queryModel)) {\n // direct match\n if (logging) {\n console.log(`Invalidating query ${JSON.stringify(queryKey)} due to mutation \"${model}.${operation}\"`);\n }\n return true;\n }\n\n if (args) {\n // traverse query args to find nested reads that match the model under mutation\n if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {\n if (logging) {\n console.log(\n `Invalidating query ${JSON.stringify(queryKey)} due to mutation \"${model}.${operation}\"`\n );\n }\n return true;\n }\n }\n\n return false;\n };\n}\n\n// find nested reads that match the given models\nfunction findNestedRead(visitingModel: string, targetModels: string[], modelMeta: ModelMeta, args: any) {\n const modelsRead = getReadModels(visitingModel, modelMeta, args);\n return targetModels.some((m) => modelsRead.includes(m));\n}\n\ntype QueryCache = {\n queryKey: readonly unknown[];\n state: {\n data: unknown;\n error: unknown;\n };\n}[];\n\ntype SetCacheFunc = (queryKey: readonly unknown[], data: unknown) => void;\n\nexport function setupOptimisticUpdate(\n model: string,\n operation: string,\n modelMeta: ModelMeta,\n options: MutationOptions,\n queryCache: QueryCache,\n setCache: SetCacheFunc,\n invalidate?: InvalidateFunc,\n logging = false\n) {\n const origOnMutate = options?.onMutate;\n const origOnSettled = options?.onSettled;\n\n options.onMutate = async (...args: unknown[]) => {\n const [variables] = args;\n await optimisticUpdate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n queryCache,\n setCache,\n logging\n );\n return origOnMutate?.(...args);\n };\n\n options.onSettled = async (...args: unknown[]) => {\n if (invalidate) {\n const [, , variables] = args;\n const predicate = await getInvalidationPredicate(\n model,\n operation as PrismaWriteActionType,\n variables,\n modelMeta,\n logging\n );\n await invalidate(predicate);\n }\n return origOnSettled?.(...args);\n };\n}\n\n// optimistically updates query cache\nasync function optimisticUpdate(\n mutationModel: string,\n mutationOp: string,\n mutationArgs: any,\n modelMeta: ModelMeta,\n queryCache: QueryCache,\n setCache: SetCacheFunc,\n logging = false\n) {\n for (const cacheItem of queryCache) {\n const {\n queryKey,\n state: { data, error },\n } = cacheItem;\n\n if (error) {\n continue;\n }\n\n const [_, queryModel, queryOp, _queryArgs, { optimisticUpdate }] = queryKey as QueryKey;\n if (!optimisticUpdate) {\n continue;\n }\n\n const mutatedData = await applyMutation(\n queryModel,\n queryOp,\n data,\n mutationModel,\n mutationOp as PrismaWriteActionType,\n mutationArgs,\n modelMeta,\n logging\n );\n\n if (mutatedData !== undefined) {\n // mutation applicable to this query, update cache\n if (logging) {\n console.log(\n `Optimistically updating query ${JSON.stringify(\n queryKey\n )} due to mutation \"${mutationModel}.${mutationOp}\"`\n );\n }\n setCache(queryKey, mutatedData);\n }\n }\n}\n"],"mappings":"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","names":["fetch","optimisticUpdate","fetch","optimisticUpdate"]}
|
package/runtime/vue.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _tanstack_vue_query from '@tanstack/vue-query';
|
|
2
2
|
import { UseQueryOptions, UseInfiniteQueryOptions, UseMutationOptions } from '@tanstack/vue-query';
|
|
3
3
|
import { ModelMeta } from '@zenstackhq/runtime/cross';
|
|
4
|
-
import { A as APIContext, F as FetchFn } from './common-
|
|
4
|
+
import { A as APIContext, F as FetchFn } from './common-82ef6965.js';
|
|
5
5
|
|
|
6
6
|
declare const VueQueryContextKey = "zenstack-vue-query-context";
|
|
7
7
|
/**
|
|
@@ -23,9 +23,11 @@ declare function getHooksContext(): {
|
|
|
23
23
|
* @param url The request URL.
|
|
24
24
|
* @param args The request args object, URL-encoded and appended as "?q=" parameter
|
|
25
25
|
* @param options The vue-query options object
|
|
26
|
+
* @param fetch The fetch function to use for sending the HTTP request
|
|
27
|
+
* @param optimisticUpdate Whether to enable automatic optimistic update
|
|
26
28
|
* @returns useQuery hook
|
|
27
29
|
*/
|
|
28
|
-
declare function useModelQuery<R>(model: string, url: string, args?: unknown, options?: UseQueryOptions<R>, fetch?: FetchFn): _tanstack_vue_query.UseQueryReturnType<R, unknown>;
|
|
30
|
+
declare function useModelQuery<R>(model: string, url: string, args?: unknown, options?: UseQueryOptions<R>, fetch?: FetchFn, optimisticUpdate?: boolean): _tanstack_vue_query.UseQueryReturnType<R, unknown>;
|
|
29
31
|
/**
|
|
30
32
|
* Creates a vue-query infinite query.
|
|
31
33
|
*
|
|
@@ -33,6 +35,7 @@ declare function useModelQuery<R>(model: string, url: string, args?: unknown, op
|
|
|
33
35
|
* @param url The request URL.
|
|
34
36
|
* @param args The initial request args object, URL-encoded and appended as "?q=" parameter
|
|
35
37
|
* @param options The vue-query infinite query options object
|
|
38
|
+
* @param fetch The fetch function to use for sending the HTTP request
|
|
36
39
|
* @returns useInfiniteQuery hook
|
|
37
40
|
*/
|
|
38
41
|
declare function useInfiniteModelQuery<R>(model: string, url: string, args?: unknown, options?: UseInfiniteQueryOptions<R>, fetch?: FetchFn): _tanstack_vue_query.UseInfiniteQueryReturnType<R, unknown>;
|
|
@@ -44,9 +47,12 @@ declare function useInfiniteModelQuery<R>(model: string, url: string, args?: unk
|
|
|
44
47
|
* @param modelMeta The model metadata.
|
|
45
48
|
* @param url The request URL.
|
|
46
49
|
* @param options The vue-query options.
|
|
50
|
+
* @param fetch The fetch function to use for sending the HTTP request
|
|
47
51
|
* @param invalidateQueries Whether to invalidate queries after mutation.
|
|
52
|
+
* @param checkReadBack Whether to check for read back errors and return undefined if found.
|
|
53
|
+
* @param optimisticUpdate Whether to enable automatic optimistic update
|
|
48
54
|
* @returns useMutation hooks
|
|
49
55
|
*/
|
|
50
|
-
declare function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(model: string, method: 'POST' | 'PUT' | 'DELETE', url: string, modelMeta: ModelMeta, options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>, fetch?: FetchFn, invalidateQueries?: boolean, checkReadBack?: C): _tanstack_vue_query.UseMutationReturnType<Result, unknown, T, unknown, Omit<_tanstack_vue_query.MutationObserverIdleResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverLoadingResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverErrorResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverSuccessResult<Result, unknown, T, unknown>, "mutate" | "reset">>;
|
|
56
|
+
declare function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(model: string, method: 'POST' | 'PUT' | 'DELETE', url: string, modelMeta: ModelMeta, options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>, fetch?: FetchFn, invalidateQueries?: boolean, checkReadBack?: C, optimisticUpdate?: boolean): _tanstack_vue_query.UseMutationReturnType<Result, unknown, T, unknown, Omit<_tanstack_vue_query.MutationObserverIdleResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverLoadingResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverErrorResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverSuccessResult<Result, unknown, T, unknown>, "mutate" | "reset">>;
|
|
51
57
|
|
|
52
58
|
export { APIContext as RequestHandlerContext, VueQueryContextKey, getHooksContext, provideHooksContext, useInfiniteModelQuery, useModelMutation, useModelQuery };
|
package/runtime/vue.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as _tanstack_vue_query from '@tanstack/vue-query';
|
|
2
2
|
import { UseQueryOptions, UseInfiniteQueryOptions, UseMutationOptions } from '@tanstack/vue-query';
|
|
3
3
|
import { ModelMeta } from '@zenstackhq/runtime/cross';
|
|
4
|
-
import { A as APIContext, F as FetchFn } from './common-
|
|
4
|
+
import { A as APIContext, F as FetchFn } from './common-82ef6965.js';
|
|
5
5
|
|
|
6
6
|
declare const VueQueryContextKey = "zenstack-vue-query-context";
|
|
7
7
|
/**
|
|
@@ -23,9 +23,11 @@ declare function getHooksContext(): {
|
|
|
23
23
|
* @param url The request URL.
|
|
24
24
|
* @param args The request args object, URL-encoded and appended as "?q=" parameter
|
|
25
25
|
* @param options The vue-query options object
|
|
26
|
+
* @param fetch The fetch function to use for sending the HTTP request
|
|
27
|
+
* @param optimisticUpdate Whether to enable automatic optimistic update
|
|
26
28
|
* @returns useQuery hook
|
|
27
29
|
*/
|
|
28
|
-
declare function useModelQuery<R>(model: string, url: string, args?: unknown, options?: UseQueryOptions<R>, fetch?: FetchFn): _tanstack_vue_query.UseQueryReturnType<R, unknown>;
|
|
30
|
+
declare function useModelQuery<R>(model: string, url: string, args?: unknown, options?: UseQueryOptions<R>, fetch?: FetchFn, optimisticUpdate?: boolean): _tanstack_vue_query.UseQueryReturnType<R, unknown>;
|
|
29
31
|
/**
|
|
30
32
|
* Creates a vue-query infinite query.
|
|
31
33
|
*
|
|
@@ -33,6 +35,7 @@ declare function useModelQuery<R>(model: string, url: string, args?: unknown, op
|
|
|
33
35
|
* @param url The request URL.
|
|
34
36
|
* @param args The initial request args object, URL-encoded and appended as "?q=" parameter
|
|
35
37
|
* @param options The vue-query infinite query options object
|
|
38
|
+
* @param fetch The fetch function to use for sending the HTTP request
|
|
36
39
|
* @returns useInfiniteQuery hook
|
|
37
40
|
*/
|
|
38
41
|
declare function useInfiniteModelQuery<R>(model: string, url: string, args?: unknown, options?: UseInfiniteQueryOptions<R>, fetch?: FetchFn): _tanstack_vue_query.UseInfiniteQueryReturnType<R, unknown>;
|
|
@@ -44,9 +47,12 @@ declare function useInfiniteModelQuery<R>(model: string, url: string, args?: unk
|
|
|
44
47
|
* @param modelMeta The model metadata.
|
|
45
48
|
* @param url The request URL.
|
|
46
49
|
* @param options The vue-query options.
|
|
50
|
+
* @param fetch The fetch function to use for sending the HTTP request
|
|
47
51
|
* @param invalidateQueries Whether to invalidate queries after mutation.
|
|
52
|
+
* @param checkReadBack Whether to check for read back errors and return undefined if found.
|
|
53
|
+
* @param optimisticUpdate Whether to enable automatic optimistic update
|
|
48
54
|
* @returns useMutation hooks
|
|
49
55
|
*/
|
|
50
|
-
declare function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(model: string, method: 'POST' | 'PUT' | 'DELETE', url: string, modelMeta: ModelMeta, options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>, fetch?: FetchFn, invalidateQueries?: boolean, checkReadBack?: C): _tanstack_vue_query.UseMutationReturnType<Result, unknown, T, unknown, Omit<_tanstack_vue_query.MutationObserverIdleResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverLoadingResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverErrorResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverSuccessResult<Result, unknown, T, unknown>, "mutate" | "reset">>;
|
|
56
|
+
declare function useModelMutation<T, R = any, C extends boolean = boolean, Result = C extends true ? R | undefined : R>(model: string, method: 'POST' | 'PUT' | 'DELETE', url: string, modelMeta: ModelMeta, options?: Omit<UseMutationOptions<Result, unknown, T, unknown>, 'mutationFn'>, fetch?: FetchFn, invalidateQueries?: boolean, checkReadBack?: C, optimisticUpdate?: boolean): _tanstack_vue_query.UseMutationReturnType<Result, unknown, T, unknown, Omit<_tanstack_vue_query.MutationObserverIdleResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverLoadingResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverErrorResult<Result, unknown, T, unknown>, "mutate" | "reset"> | Omit<_tanstack_vue_query.MutationObserverSuccessResult<Result, unknown, T, unknown>, "mutate" | "reset">>;
|
|
51
57
|
|
|
52
58
|
export { APIContext as RequestHandlerContext, VueQueryContextKey, getHooksContext, provideHooksContext, useInfiniteModelQuery, useModelMutation, useModelQuery };
|
package/runtime/vue.js
CHANGED
|
@@ -122,12 +122,12 @@ function fetcher(url, options, fetch2, checkReadBack) {
|
|
|
122
122
|
}
|
|
123
123
|
});
|
|
124
124
|
}
|
|
125
|
-
function getQueryKey(model, urlOrOperation, args) {
|
|
125
|
+
function getQueryKey(model, urlOrOperation, args, infinite = false, optimisticUpdate2 = false) {
|
|
126
126
|
if (!urlOrOperation) {
|
|
127
127
|
throw new Error("Invalid urlOrOperation");
|
|
128
128
|
}
|
|
129
129
|
const operation = urlOrOperation.split("/").pop();
|
|
130
|
-
return [QUERY_KEY_PREFIX, model, operation, args];
|
|
130
|
+
return [QUERY_KEY_PREFIX, model, operation, args, { infinite, optimisticUpdate: optimisticUpdate2 }];
|
|
131
131
|
}
|
|
132
132
|
function marshal(value) {
|
|
133
133
|
const { data, meta } = (0, import_browser.serialize)(value);
|
|
@@ -177,17 +177,19 @@ function getInvalidationPredicate(model, operation, mutationArgs, modelMeta, log
|
|
|
177
177
|
return __async(this, null, function* () {
|
|
178
178
|
const mutatedModels = yield (0, import_cross.getMutatedModels)(model, operation, mutationArgs, modelMeta);
|
|
179
179
|
return ({ queryKey }) => {
|
|
180
|
-
const [
|
|
180
|
+
const [_, queryModel, , args] = queryKey;
|
|
181
181
|
if (mutatedModels.includes(queryModel)) {
|
|
182
182
|
if (logging) {
|
|
183
|
-
console.log(`Invalidating query
|
|
183
|
+
console.log(`Invalidating query ${JSON.stringify(queryKey)} due to mutation "${model}.${operation}"`);
|
|
184
184
|
}
|
|
185
185
|
return true;
|
|
186
186
|
}
|
|
187
187
|
if (args) {
|
|
188
188
|
if (findNestedRead(queryModel, mutatedModels, modelMeta, args)) {
|
|
189
189
|
if (logging) {
|
|
190
|
-
console.log(
|
|
190
|
+
console.log(
|
|
191
|
+
`Invalidating query ${JSON.stringify(queryKey)} due to mutation "${model}.${operation}"`
|
|
192
|
+
);
|
|
191
193
|
}
|
|
192
194
|
return true;
|
|
193
195
|
}
|
|
@@ -200,6 +202,74 @@ function findNestedRead(visitingModel, targetModels, modelMeta, args) {
|
|
|
200
202
|
const modelsRead = (0, import_cross.getReadModels)(visitingModel, modelMeta, args);
|
|
201
203
|
return targetModels.some((m) => modelsRead.includes(m));
|
|
202
204
|
}
|
|
205
|
+
function setupOptimisticUpdate(model, operation, modelMeta, options, queryCache, setCache, invalidate, logging = false) {
|
|
206
|
+
const origOnMutate = options == null ? void 0 : options.onMutate;
|
|
207
|
+
const origOnSettled = options == null ? void 0 : options.onSettled;
|
|
208
|
+
options.onMutate = (...args) => __async(this, null, function* () {
|
|
209
|
+
const [variables] = args;
|
|
210
|
+
yield optimisticUpdate(
|
|
211
|
+
model,
|
|
212
|
+
operation,
|
|
213
|
+
variables,
|
|
214
|
+
modelMeta,
|
|
215
|
+
queryCache,
|
|
216
|
+
setCache,
|
|
217
|
+
logging
|
|
218
|
+
);
|
|
219
|
+
return origOnMutate == null ? void 0 : origOnMutate(...args);
|
|
220
|
+
});
|
|
221
|
+
options.onSettled = (...args) => __async(this, null, function* () {
|
|
222
|
+
if (invalidate) {
|
|
223
|
+
const [, , variables] = args;
|
|
224
|
+
const predicate = yield getInvalidationPredicate(
|
|
225
|
+
model,
|
|
226
|
+
operation,
|
|
227
|
+
variables,
|
|
228
|
+
modelMeta,
|
|
229
|
+
logging
|
|
230
|
+
);
|
|
231
|
+
yield invalidate(predicate);
|
|
232
|
+
}
|
|
233
|
+
return origOnSettled == null ? void 0 : origOnSettled(...args);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function optimisticUpdate(mutationModel, mutationOp, mutationArgs, modelMeta, queryCache, setCache, logging = false) {
|
|
237
|
+
return __async(this, null, function* () {
|
|
238
|
+
for (const cacheItem of queryCache) {
|
|
239
|
+
const {
|
|
240
|
+
queryKey,
|
|
241
|
+
state: { data, error }
|
|
242
|
+
} = cacheItem;
|
|
243
|
+
if (error) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const [_, queryModel, queryOp, _queryArgs, { optimisticUpdate: optimisticUpdate2 }] = queryKey;
|
|
247
|
+
if (!optimisticUpdate2) {
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
const mutatedData = yield (0, import_cross.applyMutation)(
|
|
251
|
+
queryModel,
|
|
252
|
+
queryOp,
|
|
253
|
+
data,
|
|
254
|
+
mutationModel,
|
|
255
|
+
mutationOp,
|
|
256
|
+
mutationArgs,
|
|
257
|
+
modelMeta,
|
|
258
|
+
logging
|
|
259
|
+
);
|
|
260
|
+
if (mutatedData !== void 0) {
|
|
261
|
+
if (logging) {
|
|
262
|
+
console.log(
|
|
263
|
+
`Optimistically updating query ${JSON.stringify(
|
|
264
|
+
queryKey
|
|
265
|
+
)} due to mutation "${mutationModel}.${mutationOp}"`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
setCache(queryKey, mutatedData);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
203
273
|
|
|
204
274
|
// src/runtime/vue.ts
|
|
205
275
|
var VueQueryContextKey = "zenstack-vue-query-context";
|
|
@@ -214,22 +284,22 @@ function getHooksContext() {
|
|
|
214
284
|
}), { endpoint } = _a, rest = __objRest(_a, ["endpoint"]);
|
|
215
285
|
return __spreadValues({ endpoint: endpoint != null ? endpoint : DEFAULT_QUERY_ENDPOINT }, rest);
|
|
216
286
|
}
|
|
217
|
-
function useModelQuery(model, url, args, options, fetch2) {
|
|
287
|
+
function useModelQuery(model, url, args, options, fetch2, optimisticUpdate2 = false) {
|
|
218
288
|
const reqUrl = makeUrl(url, args);
|
|
219
289
|
return (0, import_vue_query.useQuery)(__spreadValues({
|
|
220
|
-
queryKey: getQueryKey(model, url, args),
|
|
290
|
+
queryKey: getQueryKey(model, url, args, false, optimisticUpdate2),
|
|
221
291
|
queryFn: () => fetcher(reqUrl, void 0, fetch2, false)
|
|
222
292
|
}, options));
|
|
223
293
|
}
|
|
224
294
|
function useInfiniteModelQuery(model, url, args, options, fetch2) {
|
|
225
295
|
return (0, import_vue_query.useInfiniteQuery)(__spreadValues({
|
|
226
|
-
queryKey: getQueryKey(model, url, args),
|
|
296
|
+
queryKey: getQueryKey(model, url, args, true),
|
|
227
297
|
queryFn: ({ pageParam }) => {
|
|
228
298
|
return fetcher(makeUrl(url, pageParam != null ? pageParam : args), void 0, fetch2, false);
|
|
229
299
|
}
|
|
230
300
|
}, options));
|
|
231
301
|
}
|
|
232
|
-
function useModelMutation(model, method, url, modelMeta, options, fetch2, invalidateQueries = true, checkReadBack) {
|
|
302
|
+
function useModelMutation(model, method, url, modelMeta, options, fetch2, invalidateQueries = true, checkReadBack, optimisticUpdate2 = false) {
|
|
233
303
|
const queryClient = (0, import_vue_query.useQueryClient)();
|
|
234
304
|
const mutationFn = (data) => {
|
|
235
305
|
const reqUrl = method === "DELETE" ? makeUrl(url, data) : url;
|
|
@@ -244,10 +314,10 @@ function useModelMutation(model, method, url, modelMeta, options, fetch2, invali
|
|
|
244
314
|
return fetcher(reqUrl, fetchInit, fetch2, checkReadBack);
|
|
245
315
|
};
|
|
246
316
|
const finalOptions = __spreadProps(__spreadValues({}, options), { mutationFn });
|
|
247
|
-
|
|
317
|
+
const operation = url.split("/").pop();
|
|
318
|
+
if (operation) {
|
|
248
319
|
const { logging } = getHooksContext();
|
|
249
|
-
|
|
250
|
-
if (operation) {
|
|
320
|
+
if (invalidateQueries) {
|
|
251
321
|
setupInvalidation(
|
|
252
322
|
model,
|
|
253
323
|
operation,
|
|
@@ -257,6 +327,18 @@ function useModelMutation(model, method, url, modelMeta, options, fetch2, invali
|
|
|
257
327
|
logging
|
|
258
328
|
);
|
|
259
329
|
}
|
|
330
|
+
if (optimisticUpdate2) {
|
|
331
|
+
setupOptimisticUpdate(
|
|
332
|
+
model,
|
|
333
|
+
operation,
|
|
334
|
+
modelMeta,
|
|
335
|
+
finalOptions,
|
|
336
|
+
queryClient.getQueryCache().getAll(),
|
|
337
|
+
(queryKey, data) => queryClient.setQueryData(queryKey, data),
|
|
338
|
+
invalidateQueries ? (predicate) => queryClient.invalidateQueries({ predicate }) : void 0,
|
|
339
|
+
logging
|
|
340
|
+
);
|
|
341
|
+
}
|
|
260
342
|
}
|
|
261
343
|
return (0, import_vue_query.useMutation)(finalOptions);
|
|
262
344
|
}
|