From d8651a8ea55601f3268886f14142794c557ce6b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Wed, 24 Apr 2024 18:41:30 +0200 Subject: [PATCH 01/32] Improve directly calling queries on the client --- .../Generator/templates/sdk/wasp/client/operations/core.ts | 4 +--- .../templates/sdk/wasp/client/operations/queries/core.ts | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts index 282c4698a7..d4c1d37f16 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts @@ -10,9 +10,7 @@ import { export { configureQueryClient } from "./queryClient"; // PRIVATE API (but should maybe be public, users use values of this type) -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; +export type Query = (args: Input) => Promise // PUBLIC API export function useQuery( diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index bdc0a9db75..ef4aebde70 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -1,5 +1,5 @@ import { Route } from 'wasp/client' -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' import { type Query } from '../core.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { @@ -13,7 +13,9 @@ export function createQuery( ): QueryFor { const queryRoute = makeOperationRoute(relativeQueryPath) - async function query(queryKey, queryArgs) { + async function query(queryArgs) { + // Assumes `addMetadataToQuery` added the `queryCacheKey` property to the query. + const queryKey = (query as any).queryCacheKey const serverResult = await callOperation(queryRoute, queryArgs) return getActiveOptimisticUpdates(queryKey).reduce( (result, update) => update(result), From c7d8adf35d2979fb95442a00efb2193c833b205e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 11:38:49 +0200 Subject: [PATCH 02/32] Improve typescript support in operations --- .../sdk/wasp/client/operations/core.ts | 42 +++++++++++-------- .../wasp/client/operations/queries/core.ts | 39 ++++++++--------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts index d4c1d37f16..a790f4f2f4 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts @@ -7,42 +7,50 @@ import { useQuery as rqUseQuery, UseQueryResult, } from "@tanstack/react-query"; +import { Route } from "wasp/client"; export { configureQueryClient } from "./queryClient"; -// PRIVATE API (but should maybe be public, users use values of this type) -export type Query = (args: Input) => Promise +// PRIVATE API (but should maybe be public, users define values of this type) +export type Query = Operation // PUBLIC API export function useQuery( queryFn: Query, queryFnArgs?: Input, options?: any -): UseQueryResult; - -// PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); +): UseQueryResult { + if (typeof queryFn !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.') } - if (!queryFn.queryCacheKey) { - throw new TypeError( - "queryFn needs to have queryCacheKey property defined." - ); + const internalQueryFn = queryFn as InternalViewOf + + if (!internalQueryFn.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.') } const queryKey = queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; + ? [...internalQueryFn.queryCacheKey, queryFnArgs] + : internalQueryFn.queryCacheKey return rqUseQuery({ queryKey, - queryFn: () => queryFn(queryKey, queryFnArgs), + queryFn: () => internalQueryFn(queryFnArgs), ...options, - }); + }) +} + +// PRIVATE API (needed in SDK) +export type InternalViewOf> = Q & { + route: Route, + queryCacheKey: string[], } +// PRIVATE API (but should maybe be public, users define values of this type) +export type Action = Operation + // PRIVATE API (but should maybe be public, users use values of this type) -export type Action = [Input] extends [never] +// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 +export type Operation = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index ef4aebde70..e436a73d79 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -1,21 +1,23 @@ import { Route } from 'wasp/client' import type { _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Query } from '../core.js' +import type { Query, InternalViewOf } from '../core.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources' +// PRIVATE API (unsed in SDK) export function createQuery( relativeQueryPath: string, entitiesUsed: string[] ): QueryFor { const queryRoute = makeOperationRoute(relativeQueryPath) - async function query(queryArgs) { + type Q = QueryFor + const query: Q = async (queryArgs) => { // Assumes `addMetadataToQuery` added the `queryCacheKey` property to the query. - const queryKey = (query as any).queryCacheKey + const queryKey = (query as InternalViewOf).queryCacheKey const serverResult = await callOperation(queryRoute, queryArgs) return getActiveOptimisticUpdates(queryKey).reduce( (result, update) => update(result), @@ -28,28 +30,21 @@ export function createQuery( return query } -// PRIVATE API -export function addMetadataToQuery( - query: (...args: any[]) => Promise, - metadata: { - relativeQueryPath: string - queryRoute: Route - entitiesUsed: string[] - } -): void - -// PRIVATE API -export function addMetadataToQuery( - query, - { relativeQueryPath, queryRoute, entitiesUsed } -) { - query.queryCacheKey = [relativeQueryPath] - query.route = queryRoute - addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) +// PRIVATE API (used in SDK) +export function addMetadataToQuery( + query: Query, + { relativeQueryPath, queryRoute, entitiesUsed }: + { relativeQueryPath: string, queryRoute: Route, entitiesUsed: string[] } +): asserts query is InternalViewOf { + const internalQuery = query as InternalViewOf + + internalQuery.queryCacheKey = [relativeQueryPath] + internalQuery.route = queryRoute + addResourcesUsedByQuery(internalQuery.queryCacheKey, entitiesUsed) } export type QueryFor = Query[0], _Awaited<_ReturnType>> -type GenericBackendQuery = (args: never, context: any) => unknown \ No newline at end of file +type GenericBackendQuery = (args: never, context: any) => unknown From c309ad3289b91c02312f51d84968c0b4ea6a5853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 14:34:09 +0200 Subject: [PATCH 03/32] Improve full stack type safety --- .../templates/sdk/wasp/client/operations/actions/core.ts | 7 ++++--- .../templates/sdk/wasp/client/operations/queries/core.ts | 8 +++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts index f5db25aff2..3ca0397617 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts @@ -41,8 +41,9 @@ export function createAction( } // PRIVATE API -export type ActionFor = - Action[0], _Awaited<_ReturnType>> - +export type ActionFor = + Parameters extends [] + ? Action>> + : Action[0], _Awaited<_ReturnType>> type GenericBackendAction = (args: never, context: any) => unknown diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index e436a73d79..b27f29c9c6 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -43,8 +43,10 @@ export function addMetadataToQuery( addResourcesUsedByQuery(internalQuery.queryCacheKey, entitiesUsed) } -export type QueryFor = - Query[0], _Awaited<_ReturnType>> - +export type QueryFor = + Parameters extends [] + ? Query>> + : Query[0], _Awaited<_ReturnType>> type GenericBackendQuery = (args: never, context: any) => unknown + From 83d24dc432964aadcb85bd37c4fc0abffbdeca81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 15:00:04 +0200 Subject: [PATCH 04/32] Add e2e tests for full stack type safety --- waspc/examples/todoApp/src/TestRpcTypes.ts | 102 +++++++++++++++++++++ waspc/examples/todoApp/src/actions.ts | 2 +- waspc/examples/todoApp/src/queries.ts | 41 ++++++--- 3 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 waspc/examples/todoApp/src/TestRpcTypes.ts diff --git a/waspc/examples/todoApp/src/TestRpcTypes.ts b/waspc/examples/todoApp/src/TestRpcTypes.ts new file mode 100644 index 0000000000..068141817d --- /dev/null +++ b/waspc/examples/todoApp/src/TestRpcTypes.ts @@ -0,0 +1,102 @@ +import { + getTask, + getTasks, + createTask, + updateTaskIsDone, + deleteCompletedTasks, + toggleAllTasks, + getNumTasks, + getDate, + getAnything, + getTrueVoid, +} from 'wasp/client/operations' +import { Task } from 'wasp/entities' +import { Payload } from 'wasp/server/_types' + +// For the details of this specification, see +// https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 + +// This should be [], +// but I couldn't get it to work yet. +type VoidOperationPayload = [args?: void | undefined] + +// When the user doesn't specify an operation payload, +// we want to be as permissive as possible. +type UnspecifiedOperationPayload = [args?: unknown] + +type TQ1 = Assert< + InputsAndOutputsAre], Promise> +> + +type TQ2 = Assert< + InputsAndOutputsAre> +> + +type TQ3 = Assert< + InputsAndOutputsAre> +> + +type TQ4 = Assert< + InputsAndOutputsAre> +> + +type TQ5 = Assert< + InputsAndOutputsAre< + typeof getAnything, + UnspecifiedOperationPayload, + Promise + > +> + +type TQ6 = Assert< + InputsAndOutputsAre> +> + +type TA1 = Assert< + InputsAndOutputsAre< + typeof createTask, + [Pick], + Promise + > +> + +type TA2 = Assert< + InputsAndOutputsAre< + typeof updateTaskIsDone, + [Pick], + Promise + > +> + +type TA3 = Assert< + InputsAndOutputsAre< + typeof deleteCompletedTasks, + UnspecifiedOperationPayload, + Promise + > +> + +type TA4 = Assert< + InputsAndOutputsAre< + typeof toggleAllTasks, + UnspecifiedOperationPayload, + Promise + > +> + +type InputsAndOutputsAre< + OperationType extends (...args: any[]) => any, + ExpectedParams, + ExpectedReturn +> = { + params: AreEqual, ExpectedParams> + return: AreEqual, ExpectedReturn> +} + +type Assert = T + +type AreEqual = T extends Expected + ? Expected extends T + ? true + : false + : false diff --git a/waspc/examples/todoApp/src/actions.ts b/waspc/examples/todoApp/src/actions.ts index 995916333f..262d1daaf9 100644 --- a/waspc/examples/todoApp/src/actions.ts +++ b/waspc/examples/todoApp/src/actions.ts @@ -8,7 +8,7 @@ import { } from "wasp/server/operations"; import { getSomeResource } from './serverSetup.js' -export const createTask: CreateTask> = async ( +export const createTask: CreateTask, Task> = async ( task, context ) => { diff --git a/waspc/examples/todoApp/src/queries.ts b/waspc/examples/todoApp/src/queries.ts index d88aedb431..5163f8e051 100644 --- a/waspc/examples/todoApp/src/queries.ts +++ b/waspc/examples/todoApp/src/queries.ts @@ -1,6 +1,13 @@ -import { type Task } from "wasp/entities"; -import { HttpError } from "wasp/server"; -import { type GetNumTasks, type GetTask, type GetTasks, type GetDate } from "wasp/server/operations"; +import { type Task } from 'wasp/entities' +import { HttpError } from 'wasp/server' +import { + type GetNumTasks, + type GetTask, + type GetTasks, + type GetDate, + GetAnything, + GetTrueVoid, +} from 'wasp/server/operations' export const getTasks: GetTasks = async (_args, context) => { if (!context.user) { @@ -10,20 +17,24 @@ export const getTasks: GetTasks = async (_args, context) => { console.log('TEST_ENV_VAR', process.env.TEST_ENV_VAR) const Task = context.entities.Task - const tasks = await Task.findMany( - { - where: { user: { id: context.user.id } }, - orderBy: { id: 'asc' }, - } - ) + const tasks = await Task.findMany({ + where: { user: { id: context.user.id } }, + orderBy: { id: 'asc' }, + }) return tasks } -export const getNumTasks: GetNumTasks = async (_args, context) => { +export const getNumTasks: GetNumTasks = async ( + _args, + context +) => { return context.entities.Task.count() } -export const getTask: GetTask, Task> = async (where, context) => { +export const getTask: GetTask, Task> = async ( + where, + context +) => { if (!context.user) { throw new HttpError(401) } @@ -47,3 +58,11 @@ export const getTask: GetTask, Task> = async (where, context) = export const getDate: GetDate = async () => { return new Date() } + +export const getAnything: GetAnything = async () => { + return 'anything' +} + +export const getTrueVoid = (async () => { + return 'anything' +}) satisfies GetTrueVoid From 7f5876bdb8d71c7a02910802c4c6a1e8fe3079d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 15:54:02 +0200 Subject: [PATCH 05/32] Add more features to todoApp --- waspc/examples/todoApp/src/Todo.tsx | 29 +++++++++++++++++-- waspc/examples/todoApp/src/actions.ts | 12 ++++---- .../todoApp/src/pages/{Main.jsx => Main.tsx} | 0 waspc/examples/todoApp/src/pages/Task.tsx | 17 +++++++---- 4 files changed, 43 insertions(+), 15 deletions(-) rename waspc/examples/todoApp/src/pages/{Main.jsx => Main.tsx} (100%) diff --git a/waspc/examples/todoApp/src/Todo.tsx b/waspc/examples/todoApp/src/Todo.tsx index 3ac64a280e..b2f9ca6bd1 100644 --- a/waspc/examples/todoApp/src/Todo.tsx +++ b/waspc/examples/todoApp/src/Todo.tsx @@ -1,5 +1,5 @@ -import { Link } from "wasp/client/router"; -import { type Task } from "wasp/entities"; +import { Link } from 'wasp/client/router' +import { type Task } from 'wasp/entities' import { useAction, @@ -10,12 +10,34 @@ import { toggleAllTasks, useQuery, getTasks, -} from "wasp/client/operations"; + getTask, + getDate, + getAnything, +} from 'wasp/client/operations' import React, { useState, FormEventHandler, ChangeEventHandler } from 'react' type NonEmptyArray = [T, ...T[]] +async function logAll() { + const tasks = await getTasks() + console.info('Got tasks:', tasks) + + const someId = tasks.map((task) => task.id).find((id) => id) + if (!someId) { + console.info('No tasks found') + } else { + const task = await getTask({ id: someId }) + console.info(`Got task with id ${someId}`, task) + } + + const date = await getDate() + console.info('Got date:', date) + + const anything = await getAnything() + console.info('Got anything:', anything) +} + export function areThereAnyTasks( tasks: Task[] | undefined ): tasks is NonEmptyArray { @@ -23,6 +45,7 @@ export function areThereAnyTasks( } const Todo = () => { + logAll() const { data: tasks, isError, error: tasksError } = useQuery(getTasks) const TasksError = () => { diff --git a/waspc/examples/todoApp/src/actions.ts b/waspc/examples/todoApp/src/actions.ts index 262d1daaf9..7d1e569208 100644 --- a/waspc/examples/todoApp/src/actions.ts +++ b/waspc/examples/todoApp/src/actions.ts @@ -1,11 +1,11 @@ -import { type Task } from "wasp/entities"; -import { HttpError } from "wasp/server"; +import { type Task } from 'wasp/entities' +import { HttpError } from 'wasp/server' import { type CreateTask, type DeleteCompletedTasks, type ToggleAllTasks, type UpdateTaskIsDone, -} from "wasp/server/operations"; +} from 'wasp/server/operations' import { getSomeResource } from './serverSetup.js' export const createTask: CreateTask, Task> = async ( @@ -29,7 +29,7 @@ export const createTask: CreateTask, Task> = async ( console.log( 'New task created! Btw, current value of someResource is: ' + - getSomeResource() + getSomeResource() ) return newTask @@ -43,8 +43,8 @@ export const updateTaskIsDone: UpdateTaskIsDone< } // Uncomment to test optimistic updates - // const sleep = (ms) => new Promise(res => setTimeout(res, ms)) - // await sleep(3000); + const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms)) + await sleep(5000) const Task = context.entities.Task const updateResult = await Task.updateMany({ diff --git a/waspc/examples/todoApp/src/pages/Main.jsx b/waspc/examples/todoApp/src/pages/Main.tsx similarity index 100% rename from waspc/examples/todoApp/src/pages/Main.jsx rename to waspc/examples/todoApp/src/pages/Main.tsx diff --git a/waspc/examples/todoApp/src/pages/Task.tsx b/waspc/examples/todoApp/src/pages/Task.tsx index a3e4bbc147..303aee59fb 100644 --- a/waspc/examples/todoApp/src/pages/Task.tsx +++ b/waspc/examples/todoApp/src/pages/Task.tsx @@ -1,5 +1,5 @@ -import { Link } from "wasp/client/router"; -import { type Task } from "wasp/entities"; +import { Link } from 'wasp/client/router' +import { type Task } from 'wasp/entities' import { useAction, @@ -8,7 +8,7 @@ import { useQuery, getTask, getTasks, -} from "wasp/client/operations"; +} from 'wasp/client/operations' import React from 'react' @@ -17,7 +17,12 @@ type TaskPayload = Pick const Todo = (props: any) => { const taskId = parseInt(props.match.params.id) - const { data: task, isFetching, error, isError } = useQuery(getTask, { id: taskId }) + const { + data: task, + isFetching, + error, + isError, + } = useQuery(getTask, { id: taskId }) const updateTaskIsDoneOptimistically = useAction(updateTaskIsDone, { optimisticUpdates: [ @@ -37,8 +42,8 @@ const Todo = (props: any) => { ], }) - if (!task) return
Task with id {taskId} does not exist.
; - if (isError) return
Error occurred! {error.message}
; + if (!task) return
Task with id {taskId} does not exist.
+ if (isError) return
Error occurred! {error.message}
async function toggleIsDone({ id, isDone }: Task) { try { From 6bc94cf5d93d1f9b99ac347f25ec8c6ed5fa815c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 17:50:11 +0200 Subject: [PATCH 06/32] Make queryCacheKey visible to users --- .../templates/sdk/wasp/auth/useAuth.ts | 7 ++-- .../sdk/wasp/client/operations/core.ts | 14 +++++--- .../wasp/client/operations/queries/core.ts | 36 ++++++++++--------- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts index 2f8028d351..e6311f47e1 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts +++ b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts @@ -1,13 +1,14 @@ {{={= =}=}} import { deserialize as superjsonDeserialize } from 'superjson' import { useQuery, addMetadataToQuery } from 'wasp/client/operations' +import type { QueryFunction, Query } from 'wasp/client/operations/core' import { api, handleApiError } from 'wasp/client/api' import { HttpMethod } from 'wasp/client' import type { AuthUser } from '../server/auth/user.js' import { UseQueryResult } from '@tanstack/react-query' // PUBLIC API -export const getMe: () => Promise = createUserGetter() +export const getMe: Query = createUserGetter() // PUBLIC API export default function useAuth(queryFnArgs?: unknown, config?: any): UseQueryResult { @@ -17,7 +18,7 @@ export default function useAuth(queryFnArgs?: unknown, config?: any): UseQueryRe function createUserGetter() { const getMeRelativePath = 'auth/me' const getMeRoute = { method: HttpMethod.Get, path: `/${getMeRelativePath}` } - async function getMe(): Promise { + const getMe: QueryFunction = async () => { try { const response = await api.get(getMeRoute.path) @@ -32,7 +33,7 @@ function createUserGetter() { } addMetadataToQuery(getMe, { - relativeQueryPath: getMeRelativePath, + queryCacheKey: [getMeRelativePath], queryRoute: getMeRoute, entitiesUsed: {=& entitiesGetMeDependsOn =}, }) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts index a790f4f2f4..7fabfd7e2d 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts @@ -11,7 +11,14 @@ import { Route } from "wasp/client"; export { configureQueryClient } from "./queryClient"; // PRIVATE API (but should maybe be public, users define values of this type) -export type Query = Operation +export type QueryFunction = Operation + +export type QueryMetadata = { + queryCacheKey: string[] + route: Route +} + +export type Query = QueryFunction & QueryMetadata // PUBLIC API export function useQuery( @@ -40,10 +47,7 @@ export function useQuery( } // PRIVATE API (needed in SDK) -export type InternalViewOf> = Q & { - route: Route, - queryCacheKey: string[], -} +export type InternalViewOf> = QF & QueryMetadata // PRIVATE API (but should maybe be public, users define values of this type) export type Action = Operation diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index b27f29c9c6..d245746585 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -1,6 +1,6 @@ import { Route } from 'wasp/client' import type { _Awaited, _ReturnType } from 'wasp/universal/types' -import type { Query, InternalViewOf } from '../core.js' +import type { Query, InternalViewOf, QueryMetadata, QueryFunction } from '../core.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, @@ -13,40 +13,44 @@ export function createQuery( entitiesUsed: string[] ): QueryFor { const queryRoute = makeOperationRoute(relativeQueryPath) + const queryCacheKey = [relativeQueryPath] - type Q = QueryFor - const query: Q = async (queryArgs) => { - // Assumes `addMetadataToQuery` added the `queryCacheKey` property to the query. - const queryKey = (query as InternalViewOf).queryCacheKey + const query: QueryFunctionFor = (async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) - return getActiveOptimisticUpdates(queryKey).reduce( + return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), serverResult, ) - } + }) - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) + addMetadataToQuery(query, { queryCacheKey, queryRoute, entitiesUsed }) return query } // PRIVATE API (used in SDK) export function addMetadataToQuery( - query: Query, - { relativeQueryPath, queryRoute, entitiesUsed }: - { relativeQueryPath: string, queryRoute: Route, entitiesUsed: string[] } + query: QueryFunction, + { queryCacheKey, queryRoute, entitiesUsed }: + { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } ): asserts query is InternalViewOf { const internalQuery = query as InternalViewOf - internalQuery.queryCacheKey = [relativeQueryPath] + internalQuery.queryCacheKey = queryCacheKey internalQuery.route = queryRoute addResourcesUsedByQuery(internalQuery.queryCacheKey, entitiesUsed) } +// PRIVATE API (but should maybe be public, users define values of this type) export type QueryFor = - Parameters extends [] - ? Query>> - : Query[0], _Awaited<_ReturnType>> + QueryFunctionFor & QueryMetadata -type GenericBackendQuery = (args: never, context: any) => unknown +export type QueryFunctionFor = + Parameters extends [] + ? QueryFunction>> + : QueryFunction< + Parameters[0], + _Awaited<_ReturnType> + > +type GenericBackendQuery = (args: never, context: any) => unknown \ No newline at end of file From e8273c9cada6f7768754f5ce5e3ad412bfb02799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 18:01:36 +0200 Subject: [PATCH 07/32] Remove redundancies from useAuth hook --- waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts index e6311f47e1..2cfa10ac0c 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts +++ b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts @@ -11,9 +11,9 @@ import { UseQueryResult } from '@tanstack/react-query' export const getMe: Query = createUserGetter() // PUBLIC API -export default function useAuth(queryFnArgs?: unknown, config?: any): UseQueryResult { - return useQuery(getMe, queryFnArgs, config) -} +export default function useAuth(): UseQueryResult { + return useQuery(getMe) +} function createUserGetter() { const getMeRelativePath = 'auth/me' From 43a9d71d8fd001fe546c30b71cd4d7d2a2a8e778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 18:05:11 +0200 Subject: [PATCH 08/32] Rename InternalViewFor to QueryForFunction --- .../templates/sdk/wasp/client/operations/core.ts | 12 ++++++------ .../sdk/wasp/client/operations/queries/core.ts | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts index 7fabfd7e2d..a1ac737d50 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts @@ -29,25 +29,25 @@ export function useQuery( if (typeof queryFn !== 'function') { throw new TypeError('useQuery requires queryFn to be a function.') } - const internalQueryFn = queryFn as InternalViewOf + const query = queryFn as QueryForFunction - if (!internalQueryFn.queryCacheKey) { + if (!query.queryCacheKey) { throw new TypeError('queryFn needs to have queryCacheKey property defined.') } const queryKey = queryFnArgs !== undefined - ? [...internalQueryFn.queryCacheKey, queryFnArgs] - : internalQueryFn.queryCacheKey + ? [...query.queryCacheKey, queryFnArgs] + : query.queryCacheKey return rqUseQuery({ queryKey, - queryFn: () => internalQueryFn(queryFnArgs), + queryFn: () => query(queryFnArgs), ...options, }) } // PRIVATE API (needed in SDK) -export type InternalViewOf> = QF & QueryMetadata +export type QueryForFunction> = QF & QueryMetadata // PRIVATE API (but should maybe be public, users define values of this type) export type Action = Operation diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index d245746585..25387aa31a 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -1,6 +1,6 @@ import { Route } from 'wasp/client' import type { _Awaited, _ReturnType } from 'wasp/universal/types' -import type { Query, InternalViewOf, QueryMetadata, QueryFunction } from '../core.js' +import type { QueryFunction, QueryForFunction } from '../core.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, @@ -33,8 +33,8 @@ export function addMetadataToQuery( query: QueryFunction, { queryCacheKey, queryRoute, entitiesUsed }: { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } -): asserts query is InternalViewOf { - const internalQuery = query as InternalViewOf +): asserts query is QueryForFunction { + const internalQuery = query as QueryForFunction internalQuery.queryCacheKey = queryCacheKey internalQuery.route = queryRoute @@ -43,7 +43,7 @@ export function addMetadataToQuery( // PRIVATE API (but should maybe be public, users define values of this type) export type QueryFor = - QueryFunctionFor & QueryMetadata + QueryForFunction> export type QueryFunctionFor = Parameters extends [] From 6249c97fc7fbf817ac8ad246d11481ced0632079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 18:10:03 +0200 Subject: [PATCH 09/32] Remove redundant type assertion --- .../Generator/templates/sdk/wasp/client/operations/core.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts index a1ac737d50..defd0f6e09 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts @@ -22,14 +22,13 @@ export type Query = QueryFunction & QueryMetadata // PUBLIC API export function useQuery( - queryFn: Query, + query: Query, queryFnArgs?: Input, options?: any ): UseQueryResult { - if (typeof queryFn !== 'function') { + if (typeof query !== 'function') { throw new TypeError('useQuery requires queryFn to be a function.') } - const query = queryFn as QueryForFunction if (!query.queryCacheKey) { throw new TypeError('queryFn needs to have queryCacheKey property defined.') From f9b674a24dece5d5a05fe7269e9d1d6e562d1d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 18:15:05 +0200 Subject: [PATCH 10/32] Add one more type to be extra safe --- waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts index 2cfa10ac0c..1400c9432e 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts +++ b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts @@ -15,7 +15,7 @@ export default function useAuth(): UseQueryResult { return useQuery(getMe) } -function createUserGetter() { +function createUserGetter(): Query { const getMeRelativePath = 'auth/me' const getMeRoute = { method: HttpMethod.Get, path: `/${getMeRelativePath}` } const getMe: QueryFunction = async () => { From a6592784c51efd52ba2be449a08f1ff407cd66ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 25 Apr 2024 18:23:54 +0200 Subject: [PATCH 11/32] Improve naming --- .../sdk/wasp/client/operations/queries/core.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index 25387aa31a..749daf0e8e 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -30,22 +30,21 @@ export function createQuery( // PRIVATE API (used in SDK) export function addMetadataToQuery( - query: QueryFunction, + queryFn: QueryFunction, { queryCacheKey, queryRoute, entitiesUsed }: { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } -): asserts query is QueryForFunction { - const internalQuery = query as QueryForFunction - - internalQuery.queryCacheKey = queryCacheKey - internalQuery.route = queryRoute - addResourcesUsedByQuery(internalQuery.queryCacheKey, entitiesUsed) +): asserts queryFn is QueryForFunction { + const query = queryFn as QueryForFunction + query.queryCacheKey = queryCacheKey + query.route = queryRoute + addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) } // PRIVATE API (but should maybe be public, users define values of this type) export type QueryFor = QueryForFunction> -export type QueryFunctionFor = +type QueryFunctionFor = Parameters extends [] ? QueryFunction>> : QueryFunction< @@ -53,4 +52,4 @@ export type QueryFunctionFor = _Awaited<_ReturnType> > -type GenericBackendQuery = (args: never, context: any) => unknown \ No newline at end of file +type GenericBackendQuery = (args: never, context: any) => unknown From e81f2e4f70e1113d5dcff4e069cfb25186a71268 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Fri, 26 Apr 2024 11:09:43 +0200 Subject: [PATCH 12/32] Add type tests for getMe --- waspc/examples/todoApp/src/TestRpcTypes.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/waspc/examples/todoApp/src/TestRpcTypes.ts b/waspc/examples/todoApp/src/TestRpcTypes.ts index 068141817d..9a49eccf39 100644 --- a/waspc/examples/todoApp/src/TestRpcTypes.ts +++ b/waspc/examples/todoApp/src/TestRpcTypes.ts @@ -1,3 +1,5 @@ +import { AuthUser } from 'wasp/auth' +import { getMe } from 'wasp/client/auth' import { getTask, getTasks, @@ -52,6 +54,14 @@ type TQ6 = Assert< InputsAndOutputsAre> > +type TestGetMe = Assert< + InputsAndOutputsAre< + typeof getMe, + VoidOperationPayload, + Promise + > +> + type TA1 = Assert< InputsAndOutputsAre< typeof createTask, From 9d4e2d1c88a43de04b4b7adb019cbaf13c91d691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Fri, 26 Apr 2024 11:12:18 +0200 Subject: [PATCH 13/32] Improve function that adds metadata to queries --- .../templates/sdk/wasp/auth/useAuth.ts | 6 ++---- .../sdk/wasp/client/operations/queries/core.ts | 17 +++++++++++------ .../sdk/wasp/client/operations/queries/index.ts | 4 ++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts index 1400c9432e..f6202b520c 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts +++ b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts @@ -1,6 +1,6 @@ {{={= =}=}} import { deserialize as superjsonDeserialize } from 'superjson' -import { useQuery, addMetadataToQuery } from 'wasp/client/operations' +import { useQuery, buildAndRegisterQuery } from 'wasp/client/operations' import type { QueryFunction, Query } from 'wasp/client/operations/core' import { api, handleApiError } from 'wasp/client/api' import { HttpMethod } from 'wasp/client' @@ -32,11 +32,9 @@ function createUserGetter(): Query { } } - addMetadataToQuery(getMe, { + return buildAndRegisterQuery(getMe, { queryCacheKey: [getMeRelativePath], queryRoute: getMeRoute, entitiesUsed: {=& entitiesGetMeDependsOn =}, }) - - return getMe } diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index 749daf0e8e..d209efc6a8 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -15,7 +15,7 @@ export function createQuery( const queryRoute = makeOperationRoute(relativeQueryPath) const queryCacheKey = [relativeQueryPath] - const query: QueryFunctionFor = (async (queryArgs) => { + const queryFn: QueryFunctionFor = (async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), @@ -23,21 +23,26 @@ export function createQuery( ) }) - addMetadataToQuery(query, { queryCacheKey, queryRoute, entitiesUsed }) - - return query + return buildAndRegisterQuery( + queryFn, + { queryCacheKey, queryRoute, entitiesUsed }, + ) } // PRIVATE API (used in SDK) -export function addMetadataToQuery( +export function buildAndRegisterQuery( queryFn: QueryFunction, { queryCacheKey, queryRoute, entitiesUsed }: { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } -): asserts queryFn is QueryForFunction { +): QueryForFunction { const query = queryFn as QueryForFunction + query.queryCacheKey = queryCacheKey query.route = queryRoute addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) + + return query + } // PRIVATE API (but should maybe be public, users define values of this type) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/index.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/index.ts index ba14725469..8df916377d 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/index.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/index.ts @@ -12,5 +12,5 @@ export const {= operationName =}: QueryFor<{= operationTypeName =}> = createQuer ) {=/ queries =} -// PRIVATE API -export { addMetadataToQuery } from './core' +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core' From ccde43ab5d1d1c99f165acc495301e2800332aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Fri, 26 Apr 2024 11:42:34 +0200 Subject: [PATCH 14/32] DRY up RPC types --- .../wasp/client/operations/actions/core.ts | 14 ++++------ .../sdk/wasp/client/operations/core.ts | 28 +++++++++++++------ .../wasp/client/operations/queries/core.ts | 28 +++++++++++-------- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts index 3ca0397617..38773b5d39 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts @@ -1,5 +1,5 @@ -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Action } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { OperationRpcFor, GenericBackendOperation } from '../core.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { registerActionInProgress, @@ -7,7 +7,7 @@ import { } from '../internal/resources.js' // PRIVATE API -export function createAction( +export function createAction( relativeActionRoute: string, entitiesUsed: unknown[] ): ActionFor { @@ -41,9 +41,5 @@ export function createAction( } // PRIVATE API -export type ActionFor = - Parameters extends [] - ? Action>> - : Action[0], _Awaited<_ReturnType>> - -type GenericBackendAction = (args: never, context: any) => unknown +export type ActionFor = + OperationRpcFor diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts index defd0f6e09..50952a407e 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts @@ -8,18 +8,24 @@ import { UseQueryResult, } from "@tanstack/react-query"; import { Route } from "wasp/client"; +import type { _Awaited, _ReturnType } from 'wasp/universal/types' export { configureQueryClient } from "./queryClient"; // PRIVATE API (but should maybe be public, users define values of this type) -export type QueryFunction = Operation +export type Query = QueryFunction & QueryMetadata + +// PRIVATE API (but should maybe be public, users define values of this type) +export type Action = ClientOperation +// PRIVATE API +export type QueryFunction = ClientOperation + +// PRIVATE API export type QueryMetadata = { queryCacheKey: string[] route: Route } -export type Query = QueryFunction & QueryMetadata - // PUBLIC API export function useQuery( query: Query, @@ -46,17 +52,23 @@ export function useQuery( } // PRIVATE API (needed in SDK) -export type QueryForFunction> = QF & QueryMetadata - -// PRIVATE API (but should maybe be public, users define values of this type) -export type Action = Operation +export type OperationRpcFor = + Parameters extends [] + ? ClientOperation>> + : ClientOperation< + Parameters[0], + _Awaited<_ReturnType> + > // PRIVATE API (but should maybe be public, users use values of this type) // Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 -export type Operation = [Input] extends [never] +export type ClientOperation = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +// PRIVATE API (needed in SDK) +export type GenericBackendOperation = (args: never, context: any) => unknown + // PRIVATE API (but should maybe be public, users define values of this type) /** * An options object passed into the `useAction` hook and used to enhance the diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index d209efc6a8..73124e9a9b 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -1,6 +1,12 @@ import { Route } from 'wasp/client' import type { _Awaited, _ReturnType } from 'wasp/universal/types' -import type { QueryFunction, QueryForFunction } from '../core.js' +import type { + ClientOperation, + GenericBackendOperation, + OperationRpcFor, + QueryFunction, + QueryMetadata, +} from '../core.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, @@ -8,7 +14,7 @@ import { } from '../internal/resources' // PRIVATE API (unsed in SDK) -export function createQuery( +export function createQuery( relativeQueryPath: string, entitiesUsed: string[] ): QueryFor { @@ -31,7 +37,7 @@ export function createQuery( // PRIVATE API (used in SDK) export function buildAndRegisterQuery( - queryFn: QueryFunction, + queryFn: ClientOperation, { queryCacheKey, queryRoute, entitiesUsed }: { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } ): QueryForFunction { @@ -46,15 +52,13 @@ export function buildAndRegisterQuery( } // PRIVATE API (but should maybe be public, users define values of this type) -export type QueryFor = +export type QueryFor = QueryForFunction> -type QueryFunctionFor = - Parameters extends [] - ? QueryFunction>> - : QueryFunction< - Parameters[0], - _Awaited<_ReturnType> - > +type QueryFunctionFor = + OperationRpcFor + +// PRIVATE API (needed in SDK) +type QueryForFunction> = + QF & QueryMetadata -type GenericBackendQuery = (args: never, context: any) => unknown From 15224f8020844d1376da1f04da4dce3ab3be27e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Fri, 26 Apr 2024 16:59:22 +0200 Subject: [PATCH 15/32] Separate RPC from hooks --- .../templates/sdk/wasp/auth/useAuth.ts | 2 +- .../wasp/client/operations/actions/core.ts | 2 +- .../client/operations/{core.ts => hooks.ts} | 35 +---------------- .../sdk/wasp/client/operations/index.ts | 2 +- .../wasp/client/operations/queries/core.ts | 2 +- .../sdk/wasp/client/operations/rpc.ts | 38 +++++++++++++++++++ .../sdk/wasp/client/test/vitest/helpers.tsx | 2 +- .../Generator/templates/sdk/wasp/package.json | 2 +- waspc/examples/todoApp/src/App.tsx | 10 +++-- .../Client/OperationsGenerator.hs | 3 +- 10 files changed, 53 insertions(+), 45 deletions(-) rename waspc/data/Generator/templates/sdk/wasp/client/operations/{core.ts => hooks.ts} (90%) create mode 100644 waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts index f6202b520c..7f0d20f536 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts +++ b/waspc/data/Generator/templates/sdk/wasp/auth/useAuth.ts @@ -1,7 +1,7 @@ {{={= =}=}} import { deserialize as superjsonDeserialize } from 'superjson' import { useQuery, buildAndRegisterQuery } from 'wasp/client/operations' -import type { QueryFunction, Query } from 'wasp/client/operations/core' +import type { QueryFunction, Query } from 'wasp/client/operations/rpc' import { api, handleApiError } from 'wasp/client/api' import { HttpMethod } from 'wasp/client' import type { AuthUser } from '../server/auth/user.js' diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts index 38773b5d39..c24f726ef3 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/actions/core.ts @@ -1,5 +1,5 @@ import type { _Awaited, _ReturnType } from 'wasp/universal/types' -import type { OperationRpcFor, GenericBackendOperation } from '../core.js' +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { registerActionInProgress, diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts similarity index 90% rename from waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts rename to waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts index 50952a407e..bad5d4b647 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts @@ -7,25 +7,10 @@ import { useQuery as rqUseQuery, UseQueryResult, } from "@tanstack/react-query"; -import { Route } from "wasp/client"; import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import { Action, Query } from "./rpc"; export { configureQueryClient } from "./queryClient"; -// PRIVATE API (but should maybe be public, users define values of this type) -export type Query = QueryFunction & QueryMetadata - -// PRIVATE API (but should maybe be public, users define values of this type) -export type Action = ClientOperation - -// PRIVATE API -export type QueryFunction = ClientOperation - -// PRIVATE API -export type QueryMetadata = { - queryCacheKey: string[] - route: Route -} - // PUBLIC API export function useQuery( query: Query, @@ -51,24 +36,6 @@ export function useQuery( }) } -// PRIVATE API (needed in SDK) -export type OperationRpcFor = - Parameters extends [] - ? ClientOperation>> - : ClientOperation< - Parameters[0], - _Awaited<_ReturnType> - > - -// PRIVATE API (but should maybe be public, users use values of this type) -// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 -export type ClientOperation = [Input] extends [never] - ? (args?: unknown) => Promise - : (args: Input) => Promise; - -// PRIVATE API (needed in SDK) -export type GenericBackendOperation = (args: never, context: any) => unknown - // PRIVATE API (but should maybe be public, users define values of this type) /** * An options object passed into the `useAction` hook and used to enhance the diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/index.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/index.ts index ec9ca9f689..4dc2691035 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/index.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/index.ts @@ -10,7 +10,7 @@ export { useQuery, // PUBLIC API type OptimisticUpdateDefinition, -} from './core' +} from './hooks' export { // PUBLIC API diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index 73124e9a9b..b1930daf0f 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -6,7 +6,7 @@ import type { OperationRpcFor, QueryFunction, QueryMetadata, -} from '../core.js' +} from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts new file mode 100644 index 0000000000..329d74e685 --- /dev/null +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts @@ -0,0 +1,38 @@ +import { type Route } from "wasp/client"; +import type { + _Awaited, + _ReturnType +} from "wasp/universal/types" + +// PRIVATE API (but should maybe be public, users define values of this type) +export type Query = QueryFunction & QueryMetadata + +// PRIVATE API (but should maybe be public, users define values of this type) +export type Action = ClientOperation + +// PRIVATE API +export type QueryFunction = ClientOperation + +// PRIVATE API +export type QueryMetadata = { + queryCacheKey: string[] + route: Route +} + +// PRIVATE API (needed in SDK) +export type OperationRpcFor = + Parameters extends [] + ? ClientOperation>> + : ClientOperation< + Parameters[0], + _Awaited<_ReturnType> + > + +// PRIVATE API (but should maybe be public, users use values of this type) +// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 +export type ClientOperation = [Input] extends [never] + ? (args?: unknown) => Promise + : (args: Input) => Promise; + +// PRIVATE API (needed in SDK) +export type GenericBackendOperation = (args: never, context: any) => unknown diff --git a/waspc/data/Generator/templates/sdk/wasp/client/test/vitest/helpers.tsx b/waspc/data/Generator/templates/sdk/wasp/client/test/vitest/helpers.tsx index 8e6085f34c..96ff5e90e8 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/test/vitest/helpers.tsx +++ b/waspc/data/Generator/templates/sdk/wasp/client/test/vitest/helpers.tsx @@ -6,7 +6,7 @@ import { BrowserRouter as Router } from 'react-router-dom' import { render, RenderResult, cleanup } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { beforeAll, afterEach, afterAll } from 'vitest' -import { Query } from 'wasp/client/operations/core' +import { Query } from 'wasp/client/operations/rpc' import { config } from 'wasp/client' import { HttpMethod, Route } from 'wasp/client' diff --git a/waspc/data/Generator/templates/sdk/wasp/package.json b/waspc/data/Generator/templates/sdk/wasp/package.json index 2d62c7db0e..96a84c044e 100644 --- a/waspc/data/Generator/templates/sdk/wasp/package.json +++ b/waspc/data/Generator/templates/sdk/wasp/package.json @@ -110,7 +110,7 @@ {=! todo(filip): Fixes below are for type errors in 0.13.1, remove ASAP =} {=! Used by our code (SDK for full-stack type safety), uncodumented (but accessible) for users. =} - "./client/operations/core": "./dist/client/operations/core.js", + "./client/operations/rpc": "./dist/client/operations/rpc.js", "./server/crud/Tasks": "./dist/server/crud/Tasks.js", "./server/operations/actions": "./dist/server/operations/actions/index.js", "./server/operations/queries": "./dist/server/operations/queries/index.js", diff --git a/waspc/examples/todoApp/src/App.tsx b/waspc/examples/todoApp/src/App.tsx index 3efa385f17..d179955815 100644 --- a/waspc/examples/todoApp/src/App.tsx +++ b/waspc/examples/todoApp/src/App.tsx @@ -1,10 +1,12 @@ -import { useSocket } from "wasp/client/webSocket"; -import { Link } from "wasp/client/router"; -import { logout, useAuth } from "wasp/client/auth"; -import { useQuery, getDate } from "wasp/client/operations"; +import { useSocket } from 'wasp/client/webSocket' +import { Link } from 'wasp/client/router' +import { logout, useAuth } from 'wasp/client/auth' +import { useQuery, getDate } from 'wasp/client/operations' import './Main.css' import { getName } from './user' +// Necessary to trigger type tests. +import './TestRpcTypes' export function App({ children }: any) { const { data: user } = useAuth() diff --git a/waspc/src/Wasp/Generator/SdkGenerator/Client/OperationsGenerator.hs b/waspc/src/Wasp/Generator/SdkGenerator/Client/OperationsGenerator.hs index cc1331786a..113668526d 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator/Client/OperationsGenerator.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator/Client/OperationsGenerator.hs @@ -38,7 +38,8 @@ genOperations spec = genClientOpsFileCopy [relfile|internal/index.ts|], -- Not migrated to TS yet genClientOpsFileCopy [relfile|internal/updateHandlersMap.js|], - genClientOpsFileCopy [relfile|core.ts|], + genClientOpsFileCopy [relfile|rpc.ts|], + genClientOpsFileCopy [relfile|hooks.ts|], genClientOpsFileCopy [relfile|index.ts|], genClientOpsFileCopy [relfile|queryClient.ts|] ] From e11581e404298e5bf9f3302a658ed78b4c6df0f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Fri, 26 Apr 2024 17:35:21 +0200 Subject: [PATCH 16/32] Remove redundant import --- .../data/Generator/templates/sdk/wasp/client/operations/hooks.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts index bad5d4b647..8a2e18082e 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts @@ -7,7 +7,6 @@ import { useQuery as rqUseQuery, UseQueryResult, } from "@tanstack/react-query"; -import type { _Awaited, _ReturnType } from 'wasp/universal/types' import { Action, Query } from "./rpc"; export { configureQueryClient } from "./queryClient"; From e4f175faa761e7794201f03d38228574b2f3681d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Fri, 26 Apr 2024 17:44:16 +0200 Subject: [PATCH 17/32] Remove redundant parentheses --- .../templates/sdk/wasp/client/operations/queries/core.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index b1930daf0f..a548e4eec5 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -21,13 +21,13 @@ export function createQuery( const queryRoute = makeOperationRoute(relativeQueryPath) const queryCacheKey = [relativeQueryPath] - const queryFn: QueryFunctionFor = (async (queryArgs) => { + const queryFn: QueryFunctionFor = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), serverResult, ) - }) + } return buildAndRegisterQuery( queryFn, From 2b9f02285b7e6d3f080fa486a78bc26a0dbd27fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Mon, 29 Apr 2024 14:23:04 +0200 Subject: [PATCH 18/32] Change formatting --- .../data/Generator/templates/sdk/wasp/client/operations/rpc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts index 329d74e685..285d930f3e 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts @@ -1,7 +1,7 @@ import { type Route } from "wasp/client"; import type { _Awaited, - _ReturnType + _ReturnType, } from "wasp/universal/types" // PRIVATE API (but should maybe be public, users define values of this type) From 3c8aac535aa8cbd6ae060f2009ce2f29ecfe23e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Mon, 29 Apr 2024 14:52:51 +0200 Subject: [PATCH 19/32] Add comment explaining type --- .../Generator/templates/sdk/wasp/client/operations/rpc.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts index 285d930f3e..b5a5411d12 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts @@ -20,6 +20,11 @@ export type QueryMetadata = { } // PRIVATE API (needed in SDK) +// Explanation: +// - Custom `_Awaited` and `_ReturnType` - Read the comments above their +// definitions. +// - `Parameters extends []` - See here: +// https://github.com/wasp-lang/wasp/pull/1992/files#r1583040080 export type OperationRpcFor = Parameters extends [] ? ClientOperation>> From 3271aaa349431ff002eccdc7ea90559eda07c503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Mon, 29 Apr 2024 20:55:52 +0200 Subject: [PATCH 20/32] Update docs --- web/docs/data-model/operations/actions.md | 4 ++-- web/docs/data-model/operations/queries.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/docs/data-model/operations/actions.md b/web/docs/data-model/operations/actions.md index 365eb32ed4..9c689da382 100644 --- a/web/docs/data-model/operations/actions.md +++ b/web/docs/data-model/operations/actions.md @@ -90,7 +90,7 @@ After declaring a Wasp Action, two important things happen: Wasp will send this object over the network and pass it into the Action's implementation as its first positional argument (more on this when we look at the implementations). Such an abstraction works thanks to an HTTP API route handler Wasp generates on the server, which calls the Action's NodeJS implementation under the hood. -Generating these two functions ensures a uniform calling interface across the entire app (both client and server). +Generating these two functions ensures a similar calling interface across the entire app (both client and server). ### Implementing Actions in Node @@ -216,7 +216,7 @@ For a detailed explanation of the Action definition API (i.e., arguments and ret ### Using Actions -To use an Action, you can import it from `wasp/client/operations` and call it directly. As mentioned, the usage doesn't change depending on whether you're on the server or the client: +To use an Action on the client, you can import it from `wasp/client/operations` and call it directly. diff --git a/web/docs/data-model/operations/queries.md b/web/docs/data-model/operations/queries.md index c41733465f..81c5cacf58 100644 --- a/web/docs/data-model/operations/queries.md +++ b/web/docs/data-model/operations/queries.md @@ -94,7 +94,7 @@ After declaring a Wasp Query, two important things happen: Wasp will send this object over the network and pass it into the Query's implementation as its first positional argument (more on this when we look at the implementations). Such an abstraction works thanks to an HTTP API route handler Wasp generates on the server, which calls the Query's NodeJS implementation under the hood. -Generating these two functions ensures a uniform calling interface across the entire app (both client and server). +Generating these two functions ensures a similar calling interface across the entire app (both client and server). ### Implementing Queries in Node @@ -188,7 +188,7 @@ For a detailed explanation of the Query definition API (i.e., arguments and retu ### Using Queries -To use a Query, you can import it from `wasp/client/operations` and call it directly. As mentioned, the usage doesn't change depending on whether you're on the server or the client: +To call a Query in the client code, you can import it from `wasp/client/operations` and call it directly. From ee25c74dd14fc2138a8e308d6f2ee329f370c215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 2 May 2024 13:56:03 +0200 Subject: [PATCH 21/32] Add type modifier to imports --- waspc/examples/todoApp/src/queries.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/waspc/examples/todoApp/src/queries.ts b/waspc/examples/todoApp/src/queries.ts index 5163f8e051..c53a5c40e9 100644 --- a/waspc/examples/todoApp/src/queries.ts +++ b/waspc/examples/todoApp/src/queries.ts @@ -1,10 +1,10 @@ import { type Task } from 'wasp/entities' import { HttpError } from 'wasp/server' -import { - type GetNumTasks, - type GetTask, - type GetTasks, - type GetDate, +import type { + GetNumTasks, + GetTask, + GetTasks, + GetDate, GetAnything, GetTrueVoid, } from 'wasp/server/operations' From dcfb9c966df7c052966733931791f84d6c15caa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 2 May 2024 14:10:35 +0200 Subject: [PATCH 22/32] Reorganize type tests --- waspc/examples/todoApp/src/App.tsx | 2 +- waspc/examples/todoApp/src/testTypes/helpers.ts | 6 ++++++ waspc/examples/todoApp/src/testTypes/index.ts | 1 + .../todoApp/src/{TestRpcTypes.ts => testTypes/rpc.ts} | 10 +--------- 4 files changed, 9 insertions(+), 10 deletions(-) create mode 100644 waspc/examples/todoApp/src/testTypes/helpers.ts create mode 100644 waspc/examples/todoApp/src/testTypes/index.ts rename waspc/examples/todoApp/src/{TestRpcTypes.ts => testTypes/rpc.ts} (93%) diff --git a/waspc/examples/todoApp/src/App.tsx b/waspc/examples/todoApp/src/App.tsx index d179955815..4ea746fca3 100644 --- a/waspc/examples/todoApp/src/App.tsx +++ b/waspc/examples/todoApp/src/App.tsx @@ -6,7 +6,7 @@ import { useQuery, getDate } from 'wasp/client/operations' import './Main.css' import { getName } from './user' // Necessary to trigger type tests. -import './TestRpcTypes' +import './testTypes' export function App({ children }: any) { const { data: user } = useAuth() diff --git a/waspc/examples/todoApp/src/testTypes/helpers.ts b/waspc/examples/todoApp/src/testTypes/helpers.ts new file mode 100644 index 0000000000..58afbbd328 --- /dev/null +++ b/waspc/examples/todoApp/src/testTypes/helpers.ts @@ -0,0 +1,6 @@ +export type Assert = T +export type AreEqual = T extends Expected + ? Expected extends T + ? true + : false + : false diff --git a/waspc/examples/todoApp/src/testTypes/index.ts b/waspc/examples/todoApp/src/testTypes/index.ts new file mode 100644 index 0000000000..200ef226de --- /dev/null +++ b/waspc/examples/todoApp/src/testTypes/index.ts @@ -0,0 +1 @@ +import './rpc' diff --git a/waspc/examples/todoApp/src/TestRpcTypes.ts b/waspc/examples/todoApp/src/testTypes/rpc.ts similarity index 93% rename from waspc/examples/todoApp/src/TestRpcTypes.ts rename to waspc/examples/todoApp/src/testTypes/rpc.ts index 9a49eccf39..c4fbaef308 100644 --- a/waspc/examples/todoApp/src/TestRpcTypes.ts +++ b/waspc/examples/todoApp/src/testTypes/rpc.ts @@ -14,10 +14,10 @@ import { } from 'wasp/client/operations' import { Task } from 'wasp/entities' import { Payload } from 'wasp/server/_types' +import { Assert, AreEqual } from './helpers' // For the details of this specification, see // https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 - // This should be [], // but I couldn't get it to work yet. type VoidOperationPayload = [args?: void | undefined] @@ -102,11 +102,3 @@ type InputsAndOutputsAre< params: AreEqual, ExpectedParams> return: AreEqual, ExpectedReturn> } - -type Assert = T - -type AreEqual = T extends Expected - ? Expected extends T - ? true - : false - : false From fc5a20a1c012976ab37f61ed3fd7a4e7bef3e544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Thu, 2 May 2024 14:18:31 +0200 Subject: [PATCH 23/32] Reformat and improve types for queries/core --- .../templates/sdk/wasp/client/operations/queries/core.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index a548e4eec5..7fcee9a6fe 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -37,7 +37,7 @@ export function createQuery( // PRIVATE API (used in SDK) export function buildAndRegisterQuery( - queryFn: ClientOperation, + queryFn: QueryFunction, { queryCacheKey, queryRoute, entitiesUsed }: { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } ): QueryForFunction { @@ -61,4 +61,3 @@ type QueryFunctionFor = // PRIVATE API (needed in SDK) type QueryForFunction> = QF & QueryMetadata - From d7e15918b16ca726927ee9466bb5ab4248595e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Fri, 3 May 2024 13:09:16 +0200 Subject: [PATCH 24/32] Add comments explaining RPC types --- .../wasp/client/operations/queries/core.ts | 14 ++++++-- .../sdk/wasp/client/operations/rpc.ts | 36 ++++++++++++++++--- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index 7fcee9a6fe..df162c955b 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -1,7 +1,6 @@ import { Route } from 'wasp/client' import type { _Awaited, _ReturnType } from 'wasp/universal/types' import type { - ClientOperation, GenericBackendOperation, OperationRpcFor, QueryFunction, @@ -52,12 +51,23 @@ export function buildAndRegisterQuery( } // PRIVATE API (but should maybe be public, users define values of this type) +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ export type QueryFor = QueryForFunction> +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ type QueryFunctionFor = OperationRpcFor -// PRIVATE API (needed in SDK) +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ type QueryForFunction> = QF & QueryMetadata diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts index b5a5411d12..d4744dc8bf 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts @@ -5,15 +5,34 @@ import type { } from "wasp/universal/types" // PRIVATE API (but should maybe be public, users define values of this type) +// Frontend queries are functions with some extra properties (metadata). +// +// To simplify working with the type (i.e., referencing the type's two different +// components), we've defined it as an intersection of two distinct types: +// one representing the function (QueryFunction), and the other representing the +// metadata (QueryMetadata) . +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ export type Query = QueryFunction & QueryMetadata // PRIVATE API (but should maybe be public, users define values of this type) +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ export type Action = ClientOperation // PRIVATE API +/** + * The client Query function type. + */ export type QueryFunction = ClientOperation // PRIVATE API +/** + * All extra properties (metadata) found on a Query object type. + */ export type QueryMetadata = { queryCacheKey: string[] route: Route @@ -25,6 +44,10 @@ export type QueryMetadata = { // definitions. // - `Parameters extends []` - See here: // https://github.com/wasp-lang/wasp/pull/1992/files#r1583040080 +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ export type OperationRpcFor = Parameters extends [] ? ClientOperation>> @@ -33,11 +56,14 @@ export type OperationRpcFor = _Awaited<_ReturnType> > -// PRIVATE API (but should maybe be public, users use values of this type) +// PRIVATE API (needed in SDK) +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown + // Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 -export type ClientOperation = [Input] extends [never] +type ClientOperation = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; - -// PRIVATE API (needed in SDK) -export type GenericBackendOperation = (args: never, context: any) => unknown From d52a9318d85ffbdab38f1f41f353dee18ee034ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Fri, 3 May 2024 14:38:43 +0200 Subject: [PATCH 25/32] Add comment that links to void type issue --- waspc/examples/todoApp/src/testTypes/rpc.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/waspc/examples/todoApp/src/testTypes/rpc.ts b/waspc/examples/todoApp/src/testTypes/rpc.ts index c4fbaef308..65fe14ed25 100644 --- a/waspc/examples/todoApp/src/testTypes/rpc.ts +++ b/waspc/examples/todoApp/src/testTypes/rpc.ts @@ -19,9 +19,11 @@ import { Assert, AreEqual } from './helpers' // For the details of this specification, see // https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 // This should be [], -// but I couldn't get it to work yet. +// but I couldn't get it to work yet: https://github.com/wasp-lang/wasp/issues/2004 type VoidOperationPayload = [args?: void | undefined] +type X = Parameters + // When the user doesn't specify an operation payload, // we want to be as permissive as possible. type UnspecifiedOperationPayload = [args?: unknown] From 74d5e2a4178ae859ea5ffed9fec75e60d7df4a6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Mon, 6 May 2024 14:55:43 +0200 Subject: [PATCH 26/32] Remove unnecessary exports and add clarifying comments --- .../sdk/wasp/client/operations/hooks.ts | 86 +++++++++---------- .../sdk/wasp/client/operations/rpc.ts | 11 ++- 2 files changed, 49 insertions(+), 48 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts index 8a2e18082e..7dd0343d39 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts @@ -35,50 +35,6 @@ export function useQuery( }) } -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. - * - */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; - -// PUBLIC API -/** - * A documented (public) way to define optimistic updates. - */ -export type OptimisticUpdateDefinition = { - getQuerySpecifier: GetQuerySpecifier; - updateQuery: UpdateQuery; -}; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and returns a Wasp Query specifier. - */ -export type GetQuerySpecifier = ( - item: ActionInput -) => QuerySpecifier; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and the previous state of the cache, and returns - * the desired (new) state of the cache. - */ -export type UpdateQuery = ( - item: ActionInput, - oldData: CachedData | undefined -) => CachedData; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A public query specifier used for addressing Wasp queries. See our docs for details: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - */ -export type QuerySpecifier = [Query, ...any[]]; - // PUBLIC API /** * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). @@ -120,6 +76,48 @@ export function useAction( return (args) => mutation.mutateAsync(args); } +// PUBLIC API +/** + * A documented (public) way to define optimistic updates. + */ +export type OptimisticUpdateDefinition = { + getQuerySpecifier: GetQuerySpecifier; + updateQuery: UpdateQuery; +}; + +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; + +/** + * A function that takes an item and returns a Wasp Query specifier. + */ +type GetQuerySpecifier = ( + item: ActionInput +) => QuerySpecifier; + +/** + * A function that takes an item and the previous state of the cache, and returns + * the desired (new) state of the cache. + */ +type UpdateQuery = ( + item: ActionInput, + oldData: CachedData | undefined +) => CachedData; + +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * A public query specifier used for addressing Wasp queries. See our docs for details: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + */ +type QuerySpecifier = [Query, ...any[]]; + + /** * An internal (undocumented, private, desugared) way of defining optimistic updates. */ diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts index d4744dc8bf..c8dd886e52 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts @@ -4,7 +4,9 @@ import type { _ReturnType, } from "wasp/universal/types" -// PRIVATE API (but should maybe be public, users define values of this type) +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type). +// // Frontend queries are functions with some extra properties (metadata). // // To simplify working with the type (i.e., referencing the type's two different @@ -17,19 +19,20 @@ import type { */ export type Query = QueryFunction & QueryMetadata -// PRIVATE API (but should maybe be public, users define values of this type) +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type) /** * The client Action object type (unlike a Query, it's just a normal function). */ export type Action = ClientOperation -// PRIVATE API +// PRIVATE API (for SDK) /** * The client Query function type. */ export type QueryFunction = ClientOperation -// PRIVATE API +// PRIVATE API (for SDK) /** * All extra properties (metadata) found on a Query object type. */ From c4de9893e1487a6bb278f98efb2fff8739e9cda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Mon, 6 May 2024 16:33:50 +0200 Subject: [PATCH 27/32] Remove empty line --- .../templates/sdk/wasp/client/operations/queries/core.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index df162c955b..7cda5367b2 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -47,7 +47,6 @@ export function buildAndRegisterQuery( addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) return query - } // PRIVATE API (but should maybe be public, users define values of this type) From 606ee830d7a45a5edbca20cd024e07ae5282efc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Mon, 6 May 2024 18:42:29 +0200 Subject: [PATCH 28/32] Fix type errors in queries/core --- .../sdk/wasp/client/operations/queries/core.ts | 12 ++++++------ .../templates/sdk/wasp/client/operations/rpc.ts | 5 +++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index 7cda5367b2..98b703e5d2 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -2,8 +2,8 @@ import { Route } from 'wasp/client' import type { _Awaited, _ReturnType } from 'wasp/universal/types' import type { GenericBackendOperation, + GenericOperationRpc, OperationRpcFor, - QueryFunction, QueryMetadata, } from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' @@ -35,12 +35,12 @@ export function createQuery( } // PRIVATE API (used in SDK) -export function buildAndRegisterQuery( - queryFn: QueryFunction, +export function buildAndRegisterQuery( + queryFn: QF, { queryCacheKey, queryRoute, entitiesUsed }: { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } -): QueryForFunction { - const query = queryFn as QueryForFunction +): QueryForFunction { + const query = queryFn as QueryForFunction query.queryCacheKey = queryCacheKey query.route = queryRoute @@ -68,5 +68,5 @@ type QueryFunctionFor = * Returns the appropriate client Query object type for the provided client * Query function type. */ -type QueryForFunction> = +type QueryForFunction = QF & QueryMetadata diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts index c8dd886e52..45a8dbbf47 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/rpc.ts @@ -66,6 +66,11 @@ export type OperationRpcFor = */ export type GenericBackendOperation = (args: never, context: any) => unknown +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise + // Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 type ClientOperation = [Input] extends [never] ? (args?: unknown) => Promise From bfc6fe8493abec4b40fa0e52bd479a486ac5cb66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Mon, 6 May 2024 20:55:32 +0200 Subject: [PATCH 29/32] Fix optimistic update issues --- .../templates/sdk/wasp/client/operations/hooks.ts | 7 ++----- .../sdk/wasp/client/operations/queries/core.ts | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts index 7dd0343d39..fa913a44c1 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/hooks.ts @@ -8,6 +8,7 @@ import { UseQueryResult, } from "@tanstack/react-query"; import { Action, Query } from "./rpc"; +import { makeQueryCacheKey } from "./queries/core"; export { configureQueryClient } from "./queryClient"; // PUBLIC API @@ -24,12 +25,8 @@ export function useQuery( throw new TypeError('queryFn needs to have queryCacheKey property defined.') } - const queryKey = - queryFnArgs !== undefined - ? [...query.queryCacheKey, queryFnArgs] - : query.queryCacheKey return rqUseQuery({ - queryKey, + queryKey: makeQueryCacheKey(query, queryFnArgs), queryFn: () => query(queryFnArgs), ...options, }) diff --git a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts index 98b703e5d2..36cd6ad067 100644 --- a/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/data/Generator/templates/sdk/wasp/client/operations/queries/core.ts @@ -4,6 +4,7 @@ import type { GenericBackendOperation, GenericOperationRpc, OperationRpcFor, + Query, QueryMetadata, } from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' @@ -12,6 +13,16 @@ import { getActiveOptimisticUpdates, } from '../internal/resources' +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey( + query: Query, + payload: Input +): (string | Input)[] { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey +} + // PRIVATE API (unsed in SDK) export function createQuery( relativeQueryPath: string, @@ -22,6 +33,7 @@ export function createQuery( const queryFn: QueryFunctionFor = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) + const queryCacheKey = makeQueryCacheKey(queryFn as QueryFor, queryArgs) return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), serverResult, @@ -68,5 +80,4 @@ type QueryFunctionFor = * Returns the appropriate client Query object type for the provided client * Query function type. */ -type QueryForFunction = - QF & QueryMetadata +type QueryForFunction = QF & QueryMetadata From ab6f0146a4eae99577fa4c9234edded21af61350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Tue, 7 May 2024 11:19:18 +0200 Subject: [PATCH 30/32] Remove redundant type --- waspc/examples/todoApp/src/testTypes/rpc.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/waspc/examples/todoApp/src/testTypes/rpc.ts b/waspc/examples/todoApp/src/testTypes/rpc.ts index 65fe14ed25..4b3724bf4d 100644 --- a/waspc/examples/todoApp/src/testTypes/rpc.ts +++ b/waspc/examples/todoApp/src/testTypes/rpc.ts @@ -22,8 +22,6 @@ import { Assert, AreEqual } from './helpers' // but I couldn't get it to work yet: https://github.com/wasp-lang/wasp/issues/2004 type VoidOperationPayload = [args?: void | undefined] -type X = Parameters - // When the user doesn't specify an operation payload, // we want to be as permissive as possible. type UnspecifiedOperationPayload = [args?: unknown] From 590c33a0bdbbeee0327f9e6fb44169a19d6a64aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Tue, 7 May 2024 12:45:14 +0200 Subject: [PATCH 31/32] Update e2e tests --- .../waspBuild-golden/files.manifest | 24 +- .../waspBuild/.wasp/build/.waspchecksums | 23 +- .../wasp/client/operations/actions/core.ts | 13 +- .../client/operations/{core.ts => hooks.ts} | 126 +++---- .../build/sdk/wasp/client/operations/index.ts | 2 +- .../wasp/client/operations/queries/core.ts | 84 +++-- .../wasp/client/operations/queries/index.ts | 4 +- .../build/sdk/wasp/client/operations/rpc.ts | 77 ++++ .../sdk/wasp/client/test/vitest/helpers.tsx | 2 +- .../dist/client/operations/actions/core.d.ts | 9 +- .../wasp/dist/client/operations/core.js.map | 1 - .../wasp/dist/client/operations/hooks.d.ts} | 39 +- .../sdk/wasp/dist/client/operations/hooks.js} | 18 +- .../wasp/dist/client/operations/hooks.js.map | 1 + .../wasp/dist/client/operations/index.d.ts | 2 +- .../sdk/wasp/dist/client/operations/index.js | 2 +- .../wasp/dist/client/operations/index.js.map | 2 +- .../dist/client/operations/queries/core.d.ts | 29 +- .../dist/client/operations/queries/core.js | 26 +- .../client/operations/queries/core.js.map | 2 +- .../dist/client/operations/queries/index.d.ts | 2 +- .../dist/client/operations/queries/index.js | 4 +- .../client/operations/queries/index.js.map | 2 +- .../sdk/wasp/dist/client/operations/rpc.d.ts | 38 ++ .../sdk/wasp/dist/client/operations/rpc.js | 2 + .../wasp/dist/client/operations/rpc.js.map | 1 + .../wasp/dist/client/test/vitest/helpers.d.ts | 2 +- .../.wasp/build/sdk/wasp/package.json | 2 +- .../wasp/client/operations/actions/core.ts | 13 +- .../client/operations/{core.ts => hooks.ts} | 126 +++---- .../out/sdk/wasp/client/operations/index.ts | 2 +- .../wasp/client/operations/queries/core.ts | 84 +++-- .../wasp/client/operations/queries/index.ts | 4 +- .../out/sdk/wasp/client/operations/rpc.ts | 77 ++++ .../sdk/wasp/client/test/vitest/helpers.tsx | 2 +- .../dist/client/operations/actions/core.d.ts | 9 +- .../wasp/dist/client/operations/core.js.map | 1 - .../wasp/dist/client/operations/hooks.d.ts} | 39 +- .../sdk/wasp/dist/client/operations/hooks.js} | 18 +- .../wasp/dist/client/operations/hooks.js.map | 1 + .../wasp/dist/client/operations/index.d.ts | 2 +- .../sdk/wasp/dist/client/operations/index.js | 2 +- .../wasp/dist/client/operations/index.js.map | 2 +- .../dist/client/operations/queries/core.d.ts | 29 +- .../dist/client/operations/queries/core.js | 26 +- .../client/operations/queries/core.js.map | 2 +- .../dist/client/operations/queries/index.d.ts | 2 +- .../dist/client/operations/queries/index.js | 4 +- .../client/operations/queries/index.js.map | 2 +- .../sdk/wasp/dist/client/operations/rpc.d.ts | 38 ++ .../sdk/wasp/dist/client/operations/rpc.js | 2 + .../wasp/dist/client/operations/rpc.js.map | 1 + .../wasp/dist/client/test/vitest/helpers.d.ts | 2 +- .../waspBuild/.wasp/out/sdk/wasp/package.json | 2 +- .../waspCompile-golden/files.manifest | 12 +- .../waspCompile/.wasp/out/.waspchecksums | 23 +- .../wasp/client/operations/actions/core.ts | 13 +- .../client/operations/{core.ts => hooks.ts} | 126 +++---- .../out/sdk/wasp/client/operations/index.ts | 2 +- .../wasp/client/operations/queries/core.ts | 84 +++-- .../wasp/client/operations/queries/index.ts | 4 +- .../out/sdk/wasp/client/operations/rpc.ts | 77 ++++ .../sdk/wasp/client/test/vitest/helpers.tsx | 2 +- .../dist/client/operations/actions/core.d.ts | 9 +- .../wasp/dist/client/operations/core.js.map | 1 - .../operations/{core.d.ts => hooks.d.ts} | 39 +- .../sdk/wasp/dist/client/operations/hooks.js} | 18 +- .../wasp/dist/client/operations/hooks.js.map | 1 + .../wasp/dist/client/operations/index.d.ts | 2 +- .../sdk/wasp/dist/client/operations/index.js | 2 +- .../wasp/dist/client/operations/index.js.map | 2 +- .../dist/client/operations/queries/core.d.ts | 29 +- .../dist/client/operations/queries/core.js | 26 +- .../client/operations/queries/core.js.map | 2 +- .../dist/client/operations/queries/index.d.ts | 2 +- .../dist/client/operations/queries/index.js | 4 +- .../client/operations/queries/index.js.map | 2 +- .../sdk/wasp/dist/client/operations/rpc.d.ts | 38 ++ .../sdk/wasp/dist/client/operations/rpc.js | 2 + .../wasp/dist/client/operations/rpc.js.map | 1 + .../wasp/dist/client/test/vitest/helpers.d.ts | 2 +- .../.wasp/out/sdk/wasp/package.json | 2 +- .../waspComplexTest-golden/files.manifest | 12 +- .../waspComplexTest/.wasp/out/.waspchecksums | 25 +- .../.wasp/out/sdk/wasp/auth/useAuth.ts | 21 +- .../wasp/client/operations/actions/core.ts | 13 +- .../client/operations/{core.ts => hooks.ts} | 126 +++---- .../out/sdk/wasp/client/operations/index.ts | 2 +- .../wasp/client/operations/queries/core.ts | 84 +++-- .../wasp/client/operations/queries/index.ts | 4 +- .../out/sdk/wasp/client/operations/rpc.ts | 77 ++++ .../sdk/wasp/client/test/vitest/helpers.tsx | 2 +- .../.wasp/out/sdk/wasp/dist/auth/useAuth.d.ts | 5 +- .../.wasp/out/sdk/wasp/dist/auth/useAuth.js | 15 +- .../out/sdk/wasp/dist/auth/useAuth.js.map | 2 +- .../dist/client/operations/actions/core.d.ts | 9 +- .../wasp/dist/client/operations/core.js.map | 1 - .../operations/{core.d.ts => hooks.d.ts} | 39 +- .../sdk/wasp/dist/client/operations/hooks.js} | 18 +- .../wasp/dist/client/operations/hooks.js.map | 1 + .../wasp/dist/client/operations/index.d.ts | 2 +- .../sdk/wasp/dist/client/operations/index.js | 2 +- .../wasp/dist/client/operations/index.js.map | 2 +- .../dist/client/operations/queries/core.d.ts | 29 +- .../dist/client/operations/queries/core.js | 26 +- .../client/operations/queries/core.js.map | 2 +- .../dist/client/operations/queries/index.d.ts | 2 +- .../dist/client/operations/queries/index.js | 4 +- .../client/operations/queries/index.js.map | 2 +- .../sdk/wasp/dist/client/operations/rpc.d.ts | 38 ++ .../sdk/wasp/dist/client/operations/rpc.js | 2 + .../wasp/dist/client/operations/rpc.js.map | 1 + .../wasp/dist/client/test/vitest/helpers.d.ts | 2 +- .../.wasp/out/sdk/wasp/package.json | 2 +- .../waspJob-golden/files.manifest | 12 +- .../waspJob/.wasp/out/.waspchecksums | 23 +- .../wasp/client/operations/actions/core.ts | 13 +- .../out/sdk/wasp/client/operations/core.ts | 346 ------------------ .../out/sdk/wasp/client/operations/hooks.ts | 328 +++++++++++++++++ .../out/sdk/wasp/client/operations/index.ts | 2 +- .../wasp/client/operations/queries/core.ts | 84 +++-- .../wasp/client/operations/queries/index.ts | 4 +- .../out/sdk/wasp/client/operations/rpc.ts | 77 ++++ .../sdk/wasp/client/test/vitest/helpers.tsx | 2 +- .../dist/client/operations/actions/core.d.ts | 9 +- .../sdk/wasp/dist/client/operations/core.d.ts | 44 --- .../sdk/wasp/dist/client/operations/core.js | 171 --------- .../wasp/dist/client/operations/core.js.map | 1 - .../wasp/dist/client/operations/hooks.d.ts | 41 +++ .../sdk/wasp/dist/client/operations/hooks.js | 169 +++++++++ .../wasp/dist/client/operations/hooks.js.map | 1 + .../wasp/dist/client/operations/index.d.ts | 2 +- .../sdk/wasp/dist/client/operations/index.js | 2 +- .../wasp/dist/client/operations/index.js.map | 2 +- .../dist/client/operations/queries/core.d.ts | 29 +- .../dist/client/operations/queries/core.js | 26 +- .../client/operations/queries/core.js.map | 2 +- .../dist/client/operations/queries/index.d.ts | 2 +- .../dist/client/operations/queries/index.js | 4 +- .../client/operations/queries/index.js.map | 2 +- .../sdk/wasp/dist/client/operations/rpc.d.ts | 38 ++ .../sdk/wasp/dist/client/operations/rpc.js | 2 + .../wasp/dist/client/operations/rpc.js.map | 1 + .../wasp/dist/client/test/vitest/helpers.d.ts | 2 +- .../waspJob/.wasp/out/sdk/wasp/package.json | 2 +- .../waspMigrate-golden/files.manifest | 12 +- .../waspMigrate/.wasp/out/.waspchecksums | 23 +- .../wasp/client/operations/actions/core.ts | 13 +- .../out/sdk/wasp/client/operations/core.ts | 346 ------------------ .../out/sdk/wasp/client/operations/hooks.ts | 328 +++++++++++++++++ .../out/sdk/wasp/client/operations/index.ts | 2 +- .../wasp/client/operations/queries/core.ts | 84 +++-- .../wasp/client/operations/queries/index.ts | 4 +- .../out/sdk/wasp/client/operations/rpc.ts | 77 ++++ .../sdk/wasp/client/test/vitest/helpers.tsx | 2 +- .../dist/client/operations/actions/core.d.ts | 9 +- .../sdk/wasp/dist/client/operations/core.d.ts | 44 --- .../sdk/wasp/dist/client/operations/core.js | 171 --------- .../wasp/dist/client/operations/core.js.map | 1 - .../wasp/dist/client/operations/hooks.d.ts | 41 +++ .../sdk/wasp/dist/client/operations/hooks.js | 169 +++++++++ .../wasp/dist/client/operations/hooks.js.map | 1 + .../wasp/dist/client/operations/index.d.ts | 2 +- .../sdk/wasp/dist/client/operations/index.js | 2 +- .../wasp/dist/client/operations/index.js.map | 2 +- .../dist/client/operations/queries/core.d.ts | 29 +- .../dist/client/operations/queries/core.js | 26 +- .../client/operations/queries/core.js.map | 2 +- .../dist/client/operations/queries/index.d.ts | 2 +- .../dist/client/operations/queries/index.js | 4 +- .../client/operations/queries/index.js.map | 2 +- .../sdk/wasp/dist/client/operations/rpc.d.ts | 38 ++ .../sdk/wasp/dist/client/operations/rpc.js | 2 + .../wasp/dist/client/operations/rpc.js.map | 1 + .../wasp/dist/client/test/vitest/helpers.d.ts | 2 +- .../.wasp/out/sdk/wasp/package.json | 2 +- 176 files changed, 2963 insertions(+), 2053 deletions(-) rename waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/{core.ts => hooks.ts} (88%) create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/rpc.ts delete mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js.map rename waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/{out/sdk/wasp/dist/client/operations/core.d.ts => build/sdk/wasp/dist/client/operations/hooks.d.ts} (65%) rename waspc/e2e-test/test-outputs/{waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js => waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js} (93%) create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js.map create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.d.ts create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js.map rename waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/{core.ts => hooks.ts} (88%) create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/rpc.ts delete mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js.map rename waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/{build/sdk/wasp/dist/client/operations/core.d.ts => out/sdk/wasp/dist/client/operations/hooks.d.ts} (65%) rename waspc/e2e-test/test-outputs/{waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js => waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js} (93%) create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js create mode 100644 waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map rename waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/{core.ts => hooks.ts} (88%) create mode 100644 waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/rpc.ts delete mode 100644 waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js.map rename waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/{core.d.ts => hooks.d.ts} (65%) rename waspc/e2e-test/test-outputs/{waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js => waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js} (93%) create mode 100644 waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map create mode 100644 waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts create mode 100644 waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js create mode 100644 waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map rename waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/{core.ts => hooks.ts} (88%) create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/rpc.ts delete mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js.map rename waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/{core.d.ts => hooks.d.ts} (65%) rename waspc/e2e-test/test-outputs/{waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js => waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js} (93%) create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js create mode 100644 waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map delete mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/core.ts create mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/hooks.ts create mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/rpc.ts delete mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts delete mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js delete mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js.map create mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts create mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js create mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map create mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts create mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js create mode 100644 waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map delete mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/core.ts create mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/hooks.ts create mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/rpc.ts delete mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts delete mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js delete mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js.map create mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts create mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js create mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map create mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts create mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js create mode 100644 waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/files.manifest b/waspc/e2e-test/test-outputs/waspBuild-golden/files.manifest index b9494dcb14..95fffde173 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/files.manifest +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/files.manifest @@ -10,7 +10,7 @@ waspBuild/.wasp/build/sdk/wasp/client/config.ts waspBuild/.wasp/build/sdk/wasp/client/index.ts waspBuild/.wasp/build/sdk/wasp/client/operations/actions/core.ts waspBuild/.wasp/build/sdk/wasp/client/operations/actions/index.ts -waspBuild/.wasp/build/sdk/wasp/client/operations/core.ts +waspBuild/.wasp/build/sdk/wasp/client/operations/hooks.ts waspBuild/.wasp/build/sdk/wasp/client/operations/index.ts waspBuild/.wasp/build/sdk/wasp/client/operations/internal/index.ts waspBuild/.wasp/build/sdk/wasp/client/operations/internal/resources.js @@ -18,6 +18,7 @@ waspBuild/.wasp/build/sdk/wasp/client/operations/internal/updateHandlersMap.js waspBuild/.wasp/build/sdk/wasp/client/operations/queries/core.ts waspBuild/.wasp/build/sdk/wasp/client/operations/queries/index.ts waspBuild/.wasp/build/sdk/wasp/client/operations/queryClient.ts +waspBuild/.wasp/build/sdk/wasp/client/operations/rpc.ts waspBuild/.wasp/build/sdk/wasp/client/router/Link.tsx waspBuild/.wasp/build/sdk/wasp/client/router/index.ts waspBuild/.wasp/build/sdk/wasp/client/router/linkHelpers.ts @@ -44,9 +45,9 @@ waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/core.js.map waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/index.d.ts waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/index.js waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/index.js.map -waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.d.ts -waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js -waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js.map +waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.d.ts +waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js +waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js.map waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.d.ts waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js.map @@ -68,6 +69,9 @@ waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.js.map waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queryClient.d.ts waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queryClient.js waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queryClient.js.map +waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.d.ts +waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js +waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js.map waspBuild/.wasp/build/sdk/wasp/dist/client/router/Link.d.ts waspBuild/.wasp/build/sdk/wasp/dist/client/router/Link.jsx waspBuild/.wasp/build/sdk/wasp/dist/client/router/Link.jsx.map @@ -226,7 +230,7 @@ waspBuild/.wasp/out/sdk/wasp/client/config.ts waspBuild/.wasp/out/sdk/wasp/client/index.ts waspBuild/.wasp/out/sdk/wasp/client/operations/actions/core.ts waspBuild/.wasp/out/sdk/wasp/client/operations/actions/index.ts -waspBuild/.wasp/out/sdk/wasp/client/operations/core.ts +waspBuild/.wasp/out/sdk/wasp/client/operations/hooks.ts waspBuild/.wasp/out/sdk/wasp/client/operations/index.ts waspBuild/.wasp/out/sdk/wasp/client/operations/internal/index.ts waspBuild/.wasp/out/sdk/wasp/client/operations/internal/resources.js @@ -234,6 +238,7 @@ waspBuild/.wasp/out/sdk/wasp/client/operations/internal/updateHandlersMap.js waspBuild/.wasp/out/sdk/wasp/client/operations/queries/core.ts waspBuild/.wasp/out/sdk/wasp/client/operations/queries/index.ts waspBuild/.wasp/out/sdk/wasp/client/operations/queryClient.ts +waspBuild/.wasp/out/sdk/wasp/client/operations/rpc.ts waspBuild/.wasp/out/sdk/wasp/client/router/Link.tsx waspBuild/.wasp/out/sdk/wasp/client/router/index.ts waspBuild/.wasp/out/sdk/wasp/client/router/linkHelpers.ts @@ -260,9 +265,9 @@ waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/index.d.ts waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js.map -waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts -waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js -waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts +waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js +waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -284,6 +289,9 @@ waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queryClient.d.ts waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts +waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js +waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map waspBuild/.wasp/out/sdk/wasp/dist/client/router/Link.d.ts waspBuild/.wasp/out/sdk/wasp/dist/client/router/Link.jsx waspBuild/.wasp/out/sdk/wasp/dist/client/router/Link.jsx.map diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums index 2506030423..3a8703140e 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/.waspchecksums @@ -32,7 +32,7 @@ "file", "../out/sdk/wasp/client/operations/actions/core.ts" ], - "016623c0ebdc1b88d746fa1345015b3cb9653429abdc13a9147a952bff83a927" + "d19dba04947e4015af69d90dd160ec5f4ed020bfa905bc37bcd5d980517097ae" ], [ [ @@ -44,16 +44,16 @@ [ [ "file", - "../out/sdk/wasp/client/operations/core.ts" + "../out/sdk/wasp/client/operations/hooks.ts" ], - "bad860771b16a0d4830fab22de8b85e63c840d47dc3728728a23b8ada91061ef" + "eb4362162aad4b605781e2e33facef83935a7df4101cc0a77097ceaff3a0b360" ], [ [ "file", "../out/sdk/wasp/client/operations/index.ts" ], - "4a66c90319dd7ef0d3a8e6c1f571037c7dfd9778b9def6e951813dbc4b4dcef3" + "edcdc3798590e62b778115b3818df8cc69fa5a8bb3a7fe9fa6d6d5ea706d14c4" ], [ [ @@ -81,14 +81,14 @@ "file", "../out/sdk/wasp/client/operations/queries/core.ts" ], - "5f30328d93582f9c8444720e99f45c19c8647f052b7fbcf5f71b578b9241ac96" + "cce982751b463494c048efd683dddb8d4e617d2f354722a79961199990c7201a" ], [ [ "file", "../out/sdk/wasp/client/operations/queries/index.ts" ], - "882410504b909cc421d50a27c39952f664ba3457438ce746a95d9cab3431944c" + "c92c64425986a38f835211c2693380a8b13904cb78bbf6f6ae880e56ade51686" ], [ [ @@ -97,6 +97,13 @@ ], "5c1d87ac10513788bcde7ebc7c10601b9ad0854cddff355e8fb7e2d4685ecdef" ], + [ + [ + "file", + "../out/sdk/wasp/client/operations/rpc.ts" + ], + "5ab471422e7916c33a0931ce8d499d7d40191802ce2c6f3343b45c623a963566" + ], [ [ "file", @@ -137,7 +144,7 @@ "file", "../out/sdk/wasp/client/test/vitest/helpers.tsx" ], - "b2362e8f80134137fda2f8bb43ef7c0d7ae8aadf8a7adfa472d42d6699e9d918" + "b44ff591a2eebfff4de9fa9e9e1b89f1f22f523f03ab0febc19ff3999721b39a" ], [ [ @@ -193,7 +200,7 @@ "file", "../out/sdk/wasp/package.json" ], - "3422dd87e9e5f4aeb3922ee152ad691399d91ad71172f2b76f6235eb28955fa2" + "8df2ebcc130b484aa956ddf0109b23c83fe2221cb41ea35ed5e99817013f36a9" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/actions/core.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/actions/core.ts index f5db25aff2..c24f726ef3 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/actions/core.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/actions/core.ts @@ -1,5 +1,5 @@ -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Action } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { registerActionInProgress, @@ -7,7 +7,7 @@ import { } from '../internal/resources.js' // PRIVATE API -export function createAction( +export function createAction( relativeActionRoute: string, entitiesUsed: unknown[] ): ActionFor { @@ -41,8 +41,5 @@ export function createAction( } // PRIVATE API -export type ActionFor = - Action[0], _Awaited<_ReturnType>> - - -type GenericBackendAction = (args: never, context: any) => unknown +export type ActionFor = + OperationRpcFor diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/core.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/hooks.ts similarity index 88% rename from waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/core.ts rename to waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/hooks.ts index 282c4698a7..fa913a44c1 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/core.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/hooks.ts @@ -7,91 +7,31 @@ import { useQuery as rqUseQuery, UseQueryResult, } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; +import { makeQueryCacheKey } from "./queries/core"; export { configureQueryClient } from "./queryClient"; -// PRIVATE API (but should maybe be public, users use values of this type) -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; - // PUBLIC API export function useQuery( - queryFn: Query, + query: Query, queryFnArgs?: Input, options?: any -): UseQueryResult; - -// PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); +): UseQueryResult { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.') } - if (!queryFn.queryCacheKey) { - throw new TypeError( - "queryFn needs to have queryCacheKey property defined." - ); + + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.') } - const queryKey = - queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; return rqUseQuery({ - queryKey, - queryFn: () => queryFn(queryKey, queryFnArgs), + queryKey: makeQueryCacheKey(query, queryFnArgs), + queryFn: () => query(queryFnArgs), ...options, - }); + }) } -// PRIVATE API (but should maybe be public, users use values of this type) -export type Action = [Input] extends [never] - ? (args?: unknown) => Promise - : (args: Input) => Promise; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. - * - */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; - -// PUBLIC API -/** - * A documented (public) way to define optimistic updates. - */ -export type OptimisticUpdateDefinition = { - getQuerySpecifier: GetQuerySpecifier; - updateQuery: UpdateQuery; -}; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and returns a Wasp Query specifier. - */ -export type GetQuerySpecifier = ( - item: ActionInput -) => QuerySpecifier; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and the previous state of the cache, and returns - * the desired (new) state of the cache. - */ -export type UpdateQuery = ( - item: ActionInput, - oldData: CachedData | undefined -) => CachedData; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A public query specifier used for addressing Wasp queries. See our docs for details: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - */ -export type QuerySpecifier = [Query, ...any[]]; - // PUBLIC API /** * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). @@ -133,6 +73,48 @@ export function useAction( return (args) => mutation.mutateAsync(args); } +// PUBLIC API +/** + * A documented (public) way to define optimistic updates. + */ +export type OptimisticUpdateDefinition = { + getQuerySpecifier: GetQuerySpecifier; + updateQuery: UpdateQuery; +}; + +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; + +/** + * A function that takes an item and returns a Wasp Query specifier. + */ +type GetQuerySpecifier = ( + item: ActionInput +) => QuerySpecifier; + +/** + * A function that takes an item and the previous state of the cache, and returns + * the desired (new) state of the cache. + */ +type UpdateQuery = ( + item: ActionInput, + oldData: CachedData | undefined +) => CachedData; + +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * A public query specifier used for addressing Wasp queries. See our docs for details: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + */ +type QuerySpecifier = [Query, ...any[]]; + + /** * An internal (undocumented, private, desugared) way of defining optimistic updates. */ diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/index.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/index.ts index ec9ca9f689..4dc2691035 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/index.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/index.ts @@ -10,7 +10,7 @@ export { useQuery, // PUBLIC API type OptimisticUpdateDefinition, -} from './core' +} from './hooks' export { // PUBLIC API diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/queries/core.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/queries/core.ts index bdc0a9db75..36cd6ad067 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/queries/core.ts @@ -1,53 +1,83 @@ import { Route } from 'wasp/client' -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Query } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { + GenericBackendOperation, + GenericOperationRpc, + OperationRpcFor, + Query, + QueryMetadata, +} from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources' -export function createQuery( +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey( + query: Query, + payload: Input +): (string | Input)[] { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey +} + +// PRIVATE API (unsed in SDK) +export function createQuery( relativeQueryPath: string, entitiesUsed: string[] ): QueryFor { const queryRoute = makeOperationRoute(relativeQueryPath) + const queryCacheKey = [relativeQueryPath] - async function query(queryKey, queryArgs) { + const queryFn: QueryFunctionFor = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) - return getActiveOptimisticUpdates(queryKey).reduce( + const queryCacheKey = makeQueryCacheKey(queryFn as QueryFor, queryArgs) + return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), serverResult, ) } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) - - return query + return buildAndRegisterQuery( + queryFn, + { queryCacheKey, queryRoute, entitiesUsed }, + ) } -// PRIVATE API -export function addMetadataToQuery( - query: (...args: any[]) => Promise, - metadata: { - relativeQueryPath: string - queryRoute: Route - entitiesUsed: string[] - } -): void - -// PRIVATE API -export function addMetadataToQuery( - query, - { relativeQueryPath, queryRoute, entitiesUsed } -) { - query.queryCacheKey = [relativeQueryPath] +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery( + queryFn: QF, + { queryCacheKey, queryRoute, entitiesUsed }: + { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } +): QueryForFunction { + const query = queryFn as QueryForFunction + + query.queryCacheKey = queryCacheKey query.route = queryRoute addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) + + return query } -export type QueryFor = - Query[0], _Awaited<_ReturnType>> +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = + QueryForFunction> +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = + OperationRpcFor -type GenericBackendQuery = (args: never, context: any) => unknown \ No newline at end of file +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/queries/index.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/queries/index.ts index eeb2cf5a11..af63c67c63 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/queries/index.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/queries/index.ts @@ -1,4 +1,4 @@ import { type QueryFor, createQuery } from './core' -// PRIVATE API -export { addMetadataToQuery } from './core' +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core' diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/rpc.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/rpc.ts new file mode 100644 index 0000000000..45a8dbbf47 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/operations/rpc.ts @@ -0,0 +1,77 @@ +import { type Route } from "wasp/client"; +import type { + _Awaited, + _ReturnType, +} from "wasp/universal/types" + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type). +// +// Frontend queries are functions with some extra properties (metadata). +// +// To simplify working with the type (i.e., referencing the type's two different +// components), we've defined it as an intersection of two distinct types: +// one representing the function (QueryFunction), and the other representing the +// metadata (QueryMetadata) . +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type) +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation + +// PRIVATE API (for SDK) +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation + +// PRIVATE API (for SDK) +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[] + route: Route +} + +// PRIVATE API (needed in SDK) +// Explanation: +// - Custom `_Awaited` and `_ReturnType` - Read the comments above their +// definitions. +// - `Parameters extends []` - See here: +// https://github.com/wasp-lang/wasp/pull/1992/files#r1583040080 +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = + Parameters extends [] + ? ClientOperation>> + : ClientOperation< + Parameters[0], + _Awaited<_ReturnType> + > + +// PRIVATE API (needed in SDK) +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown + +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise + +// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 +type ClientOperation = [Input] extends [never] + ? (args?: unknown) => Promise + : (args: Input) => Promise; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/test/vitest/helpers.tsx b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/test/vitest/helpers.tsx index 8e6085f34c..96ff5e90e8 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/test/vitest/helpers.tsx +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/client/test/vitest/helpers.tsx @@ -6,7 +6,7 @@ import { BrowserRouter as Router } from 'react-router-dom' import { render, RenderResult, cleanup } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { beforeAll, afterEach, afterAll } from 'vitest' -import { Query } from 'wasp/client/operations/core' +import { Query } from 'wasp/client/operations/rpc' import { config } from 'wasp/client' import { HttpMethod, Route } from 'wasp/client' diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/core.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/core.d.ts index e1708451f8..4b8c455fd4 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/actions/core.d.ts @@ -1,6 +1,3 @@ -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Action } from '../core.js'; -export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; -export type ActionFor = Action[0], _Awaited<_ReturnType>>; -type GenericBackendAction = (args: never, context: any) => unknown; -export {}; +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js'; +export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; +export type ActionFor = OperationRpcFor; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js.map deleted file mode 100644 index 20d72dc15e..0000000000 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.d.ts similarity index 65% rename from waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts rename to waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.d.ts index a23b24ebd6..36a5e0b65b 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.d.ts @@ -1,18 +1,15 @@ import { UseQueryResult } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; export { configureQueryClient } from "./queryClient"; -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; -export declare function useQuery(queryFn: Query, queryFnArgs?: Input, options?: any): UseQueryResult; -export type Action = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export declare function useQuery(query: Query, queryFnArgs?: Input, options?: any): UseQueryResult; /** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; +export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; /** * A documented (public) way to define optimistic updates. */ @@ -20,25 +17,25 @@ export type OptimisticUpdateDefinition = { getQuerySpecifier: GetQuerySpecifier; updateQuery: UpdateQuery; }; +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; /** * A function that takes an item and returns a Wasp Query specifier. */ -export type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; +type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; /** * A function that takes an item and the previous state of the cache, and returns * the desired (new) state of the cache. */ -export type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; +type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; /** * A public query specifier used for addressing Wasp queries. See our docs for details: * https://wasp-lang.dev/docs/language/features#the-useaction-hook. */ -export type QuerySpecifier = [Query, ...any[]]; -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; +type QuerySpecifier = [Query, ...any[]]; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js similarity index 93% rename from waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js rename to waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js index 2c94cb01fd..95ab379515 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js @@ -1,17 +1,15 @@ import { useMutation, useQueryClient, useQuery as rqUseQuery, } from "@tanstack/react-query"; +import { makeQueryCacheKey } from "./queries/core"; export { configureQueryClient } from "./queryClient"; // PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); +export function useQuery(query, queryFnArgs, options) { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.'); } - if (!queryFn.queryCacheKey) { - throw new TypeError("queryFn needs to have queryCacheKey property defined."); + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.'); } - const queryKey = queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; - return rqUseQuery(Object.assign({ queryKey, queryFn: () => queryFn(queryKey, queryFnArgs) }, options)); + return rqUseQuery(Object.assign({ queryKey: makeQueryCacheKey(query, queryFnArgs), queryFn: () => query(queryFnArgs) }, options)); } // PUBLIC API /** @@ -168,4 +166,4 @@ function getRqQueryKeyFromSpecifier(querySpecifier) { const [queryFn, ...otherKeys] = querySpecifier; return [...queryFn.queryCacheKey, ...otherKeys]; } -//# sourceMappingURL=core.js.map \ No newline at end of file +//# sourceMappingURL=hooks.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js.map new file mode 100644 index 0000000000..9048c71ee2 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/hooks.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../client/operations/hooks.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.d.ts index 301165fa8e..76ad094f0d 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.d.ts @@ -1,4 +1,4 @@ export * from './actions'; export * from './queries'; -export { useAction, useQuery, type OptimisticUpdateDefinition, } from './core'; +export { useAction, useQuery, type OptimisticUpdateDefinition, } from './hooks'; export { configureQueryClient, initializeQueryClient, queryClientInitialized } from './queryClient'; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js index f83307c7b1..fd2c6b29b0 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js @@ -6,7 +6,7 @@ export { // PUBLIC API useAction, // PUBLIC API -useQuery, } from './core'; +useQuery, } from './hooks'; export { // PUBLIC API configureQueryClient, diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js.map index 982c957a9a..a6cf9161ab 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,QAAQ,CAAA;AAEf,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,SAAS,CAAA;AAEhB,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.d.ts index 93bbd1ddaa..c70de80ba6 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.d.ts @@ -1,12 +1,25 @@ import { Route } from 'wasp/client'; -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Query } from '../core.js'; -export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; -export declare function addMetadataToQuery(query: (...args: any[]) => Promise, metadata: { - relativeQueryPath: string; +import type { GenericBackendOperation, GenericOperationRpc, OperationRpcFor, Query, QueryMetadata } from '../rpc.js'; +export declare function makeQueryCacheKey(query: Query, payload: Input): (string | Input)[]; +export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; +export declare function buildAndRegisterQuery(queryFn: QF, { queryCacheKey, queryRoute, entitiesUsed }: { + queryCacheKey: string[]; queryRoute: Route; entitiesUsed: string[]; -}): void; -export type QueryFor = Query[0], _Awaited<_ReturnType>>; -type GenericBackendQuery = (args: never, context: any) => unknown; +}): QueryForFunction; +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = QueryForFunction>; +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = OperationRpcFor; +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata; export {}; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.js index c03f172443..fefdfc58fc 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.js @@ -1,18 +1,28 @@ import { callOperation, makeOperationRoute } from '../internal/index.js'; import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources'; +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey(query, payload) { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey; +} +// PRIVATE API (unsed in SDK) export function createQuery(relativeQueryPath, entitiesUsed) { const queryRoute = makeOperationRoute(relativeQueryPath); - async function query(queryKey, queryArgs) { + const queryCacheKey = [relativeQueryPath]; + const queryFn = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs); - return getActiveOptimisticUpdates(queryKey).reduce((result, update) => update(result), serverResult); - } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }); - return query; + const queryCacheKey = makeQueryCacheKey(queryFn, queryArgs); + return getActiveOptimisticUpdates(queryCacheKey).reduce((result, update) => update(result), serverResult); + }; + return buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }); } -// PRIVATE API -export function addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) { - query.queryCacheKey = [relativeQueryPath]; +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }) { + const query = queryFn; + query.queryCacheKey = queryCacheKey; query.route = queryRoute; addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed); + return query; } //# sourceMappingURL=core.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.js.map index dcc40d2693..0ef0547c44 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IAExD,KAAK,UAAU,KAAK,CAAC,QAAQ,EAAE,SAAS;QACtC,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,OAAO,0BAA0B,CAAC,QAAQ,CAAC,CAAC,MAAM,CAChD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAA;IAE1E,OAAO,KAAK,CAAA;AACd,CAAC;AAYD,cAAc;AACd,MAAM,UAAU,kBAAkB,CAChC,KAAK,EACL,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE;IAE/C,KAAK,CAAC,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IACzC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;AAC5D,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,gCAAgC;AAChC,MAAM,UAAU,iBAAiB,CAC/B,KAA2B,EAC3B,OAAc;IAEd,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC;QAC5B,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,aAAa,CAAA;AAC3B,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IACxD,MAAM,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAEzC,MAAM,OAAO,GAAmC,KAAK,EAAE,SAAS,EAAE,EAAE;QAClE,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,MAAM,aAAa,GAAG,iBAAiB,CAAC,OAAiC,EAAE,SAAS,CAAC,CAAA;QACrF,OAAO,0BAA0B,CAAC,aAAa,CAAC,CAAC,MAAM,CACrD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC,CAAA;IAED,OAAO,qBAAqB,CAC1B,OAAO,EACP,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,CAC5C,CAAA;AACH,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,qBAAqB,CACnC,OAAW,EACX,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAC6B;IAEtE,MAAM,KAAK,GAAG,OAA+B,CAAA;IAE7C,KAAK,CAAC,aAAa,GAAG,aAAa,CAAA;IACnC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IAE1D,OAAO,KAAK,CAAA;AACd,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.d.ts index 575c502be1..2d9dbafe81 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.d.ts @@ -1 +1 @@ -export { addMetadataToQuery } from './core'; +export { buildAndRegisterQuery } from './core'; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.js index 1c28e8d0d3..56d2e15238 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.js @@ -1,3 +1,3 @@ -// PRIVATE API -export { addMetadataToQuery } from './core'; +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.js.map index 5c83611fa3..44416efcfa 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/queries/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.d.ts new file mode 100644 index 0000000000..ee52ec65b4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.d.ts @@ -0,0 +1,38 @@ +import { type Route } from "wasp/client"; +import type { _Awaited, _ReturnType } from "wasp/universal/types"; +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata; +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation; +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation; +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[]; + route: Route; +}; +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = Parameters extends [] ? ClientOperation>> : ClientOperation[0], _Awaited<_ReturnType>>; +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown; +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise; +type ClientOperation = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export {}; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js new file mode 100644 index 0000000000..f3a500abe4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=rpc.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js.map new file mode 100644 index 0000000000..a51bf309e5 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/rpc.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../client/operations/rpc.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/test/vitest/helpers.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/test/vitest/helpers.d.ts index 645112861a..89fd0d7587 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/test/vitest/helpers.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/test/vitest/helpers.d.ts @@ -1,7 +1,7 @@ import { ReactElement } from 'react'; import { type SetupServer } from 'msw/node'; import { RenderResult } from '@testing-library/react'; -import { Query } from 'wasp/client/operations/core'; +import { Query } from 'wasp/client/operations/rpc'; import { Route } from 'wasp/client'; export type MockQuery = (query: Query, resJson: MockOutput) => void; export type MockApi = (route: Route, resJson: unknown) => void; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/package.json index e3a3bb5440..73e355a456 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/package.json @@ -41,7 +41,7 @@ "./client/auth": "./dist/client/auth/index.js", "./client/crud": "./dist/client/crud/index.js", "./client/operations": "./dist/client/operations/index.js", - "./client/operations/core": "./dist/client/operations/core.js", + "./client/operations/rpc": "./dist/client/operations/rpc.js", "./client/router": "./dist/client/router/index.js", "./client/test": "./dist/client/test/index.js", "./client/test/*": "./dist/client/test/*.js", diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/actions/core.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/actions/core.ts index f5db25aff2..c24f726ef3 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/actions/core.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/actions/core.ts @@ -1,5 +1,5 @@ -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Action } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { registerActionInProgress, @@ -7,7 +7,7 @@ import { } from '../internal/resources.js' // PRIVATE API -export function createAction( +export function createAction( relativeActionRoute: string, entitiesUsed: unknown[] ): ActionFor { @@ -41,8 +41,5 @@ export function createAction( } // PRIVATE API -export type ActionFor = - Action[0], _Awaited<_ReturnType>> - - -type GenericBackendAction = (args: never, context: any) => unknown +export type ActionFor = + OperationRpcFor diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/core.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/hooks.ts similarity index 88% rename from waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/core.ts rename to waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/hooks.ts index 282c4698a7..fa913a44c1 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/core.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/hooks.ts @@ -7,91 +7,31 @@ import { useQuery as rqUseQuery, UseQueryResult, } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; +import { makeQueryCacheKey } from "./queries/core"; export { configureQueryClient } from "./queryClient"; -// PRIVATE API (but should maybe be public, users use values of this type) -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; - // PUBLIC API export function useQuery( - queryFn: Query, + query: Query, queryFnArgs?: Input, options?: any -): UseQueryResult; - -// PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); +): UseQueryResult { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.') } - if (!queryFn.queryCacheKey) { - throw new TypeError( - "queryFn needs to have queryCacheKey property defined." - ); + + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.') } - const queryKey = - queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; return rqUseQuery({ - queryKey, - queryFn: () => queryFn(queryKey, queryFnArgs), + queryKey: makeQueryCacheKey(query, queryFnArgs), + queryFn: () => query(queryFnArgs), ...options, - }); + }) } -// PRIVATE API (but should maybe be public, users use values of this type) -export type Action = [Input] extends [never] - ? (args?: unknown) => Promise - : (args: Input) => Promise; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. - * - */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; - -// PUBLIC API -/** - * A documented (public) way to define optimistic updates. - */ -export type OptimisticUpdateDefinition = { - getQuerySpecifier: GetQuerySpecifier; - updateQuery: UpdateQuery; -}; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and returns a Wasp Query specifier. - */ -export type GetQuerySpecifier = ( - item: ActionInput -) => QuerySpecifier; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and the previous state of the cache, and returns - * the desired (new) state of the cache. - */ -export type UpdateQuery = ( - item: ActionInput, - oldData: CachedData | undefined -) => CachedData; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A public query specifier used for addressing Wasp queries. See our docs for details: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - */ -export type QuerySpecifier = [Query, ...any[]]; - // PUBLIC API /** * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). @@ -133,6 +73,48 @@ export function useAction( return (args) => mutation.mutateAsync(args); } +// PUBLIC API +/** + * A documented (public) way to define optimistic updates. + */ +export type OptimisticUpdateDefinition = { + getQuerySpecifier: GetQuerySpecifier; + updateQuery: UpdateQuery; +}; + +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; + +/** + * A function that takes an item and returns a Wasp Query specifier. + */ +type GetQuerySpecifier = ( + item: ActionInput +) => QuerySpecifier; + +/** + * A function that takes an item and the previous state of the cache, and returns + * the desired (new) state of the cache. + */ +type UpdateQuery = ( + item: ActionInput, + oldData: CachedData | undefined +) => CachedData; + +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * A public query specifier used for addressing Wasp queries. See our docs for details: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + */ +type QuerySpecifier = [Query, ...any[]]; + + /** * An internal (undocumented, private, desugared) way of defining optimistic updates. */ diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/index.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/index.ts index ec9ca9f689..4dc2691035 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/index.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/index.ts @@ -10,7 +10,7 @@ export { useQuery, // PUBLIC API type OptimisticUpdateDefinition, -} from './core' +} from './hooks' export { // PUBLIC API diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/queries/core.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/queries/core.ts index bdc0a9db75..36cd6ad067 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/queries/core.ts @@ -1,53 +1,83 @@ import { Route } from 'wasp/client' -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Query } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { + GenericBackendOperation, + GenericOperationRpc, + OperationRpcFor, + Query, + QueryMetadata, +} from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources' -export function createQuery( +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey( + query: Query, + payload: Input +): (string | Input)[] { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey +} + +// PRIVATE API (unsed in SDK) +export function createQuery( relativeQueryPath: string, entitiesUsed: string[] ): QueryFor { const queryRoute = makeOperationRoute(relativeQueryPath) + const queryCacheKey = [relativeQueryPath] - async function query(queryKey, queryArgs) { + const queryFn: QueryFunctionFor = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) - return getActiveOptimisticUpdates(queryKey).reduce( + const queryCacheKey = makeQueryCacheKey(queryFn as QueryFor, queryArgs) + return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), serverResult, ) } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) - - return query + return buildAndRegisterQuery( + queryFn, + { queryCacheKey, queryRoute, entitiesUsed }, + ) } -// PRIVATE API -export function addMetadataToQuery( - query: (...args: any[]) => Promise, - metadata: { - relativeQueryPath: string - queryRoute: Route - entitiesUsed: string[] - } -): void - -// PRIVATE API -export function addMetadataToQuery( - query, - { relativeQueryPath, queryRoute, entitiesUsed } -) { - query.queryCacheKey = [relativeQueryPath] +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery( + queryFn: QF, + { queryCacheKey, queryRoute, entitiesUsed }: + { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } +): QueryForFunction { + const query = queryFn as QueryForFunction + + query.queryCacheKey = queryCacheKey query.route = queryRoute addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) + + return query } -export type QueryFor = - Query[0], _Awaited<_ReturnType>> +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = + QueryForFunction> +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = + OperationRpcFor -type GenericBackendQuery = (args: never, context: any) => unknown \ No newline at end of file +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/queries/index.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/queries/index.ts index eeb2cf5a11..af63c67c63 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/queries/index.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/queries/index.ts @@ -1,4 +1,4 @@ import { type QueryFor, createQuery } from './core' -// PRIVATE API -export { addMetadataToQuery } from './core' +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core' diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/rpc.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/rpc.ts new file mode 100644 index 0000000000..45a8dbbf47 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/operations/rpc.ts @@ -0,0 +1,77 @@ +import { type Route } from "wasp/client"; +import type { + _Awaited, + _ReturnType, +} from "wasp/universal/types" + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type). +// +// Frontend queries are functions with some extra properties (metadata). +// +// To simplify working with the type (i.e., referencing the type's two different +// components), we've defined it as an intersection of two distinct types: +// one representing the function (QueryFunction), and the other representing the +// metadata (QueryMetadata) . +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type) +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation + +// PRIVATE API (for SDK) +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation + +// PRIVATE API (for SDK) +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[] + route: Route +} + +// PRIVATE API (needed in SDK) +// Explanation: +// - Custom `_Awaited` and `_ReturnType` - Read the comments above their +// definitions. +// - `Parameters extends []` - See here: +// https://github.com/wasp-lang/wasp/pull/1992/files#r1583040080 +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = + Parameters extends [] + ? ClientOperation>> + : ClientOperation< + Parameters[0], + _Awaited<_ReturnType> + > + +// PRIVATE API (needed in SDK) +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown + +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise + +// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 +type ClientOperation = [Input] extends [never] + ? (args?: unknown) => Promise + : (args: Input) => Promise; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx index 8e6085f34c..96ff5e90e8 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx @@ -6,7 +6,7 @@ import { BrowserRouter as Router } from 'react-router-dom' import { render, RenderResult, cleanup } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { beforeAll, afterEach, afterAll } from 'vitest' -import { Query } from 'wasp/client/operations/core' +import { Query } from 'wasp/client/operations/rpc' import { config } from 'wasp/client' import { HttpMethod, Route } from 'wasp/client' diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts index e1708451f8..4b8c455fd4 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts @@ -1,6 +1,3 @@ -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Action } from '../core.js'; -export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; -export type ActionFor = Action[0], _Awaited<_ReturnType>>; -type GenericBackendAction = (args: never, context: any) => unknown; -export {}; +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js'; +export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; +export type ActionFor = OperationRpcFor; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js.map deleted file mode 100644 index 20d72dc15e..0000000000 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts similarity index 65% rename from waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.d.ts rename to waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts index a23b24ebd6..36a5e0b65b 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts @@ -1,18 +1,15 @@ import { UseQueryResult } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; export { configureQueryClient } from "./queryClient"; -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; -export declare function useQuery(queryFn: Query, queryFnArgs?: Input, options?: any): UseQueryResult; -export type Action = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export declare function useQuery(query: Query, queryFnArgs?: Input, options?: any): UseQueryResult; /** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; +export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; /** * A documented (public) way to define optimistic updates. */ @@ -20,25 +17,25 @@ export type OptimisticUpdateDefinition = { getQuerySpecifier: GetQuerySpecifier; updateQuery: UpdateQuery; }; +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; /** * A function that takes an item and returns a Wasp Query specifier. */ -export type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; +type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; /** * A function that takes an item and the previous state of the cache, and returns * the desired (new) state of the cache. */ -export type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; +type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; /** * A public query specifier used for addressing Wasp queries. See our docs for details: * https://wasp-lang.dev/docs/language/features#the-useaction-hook. */ -export type QuerySpecifier = [Query, ...any[]]; -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; +type QuerySpecifier = [Query, ...any[]]; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js similarity index 93% rename from waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js rename to waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js index 2c94cb01fd..95ab379515 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js @@ -1,17 +1,15 @@ import { useMutation, useQueryClient, useQuery as rqUseQuery, } from "@tanstack/react-query"; +import { makeQueryCacheKey } from "./queries/core"; export { configureQueryClient } from "./queryClient"; // PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); +export function useQuery(query, queryFnArgs, options) { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.'); } - if (!queryFn.queryCacheKey) { - throw new TypeError("queryFn needs to have queryCacheKey property defined."); + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.'); } - const queryKey = queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; - return rqUseQuery(Object.assign({ queryKey, queryFn: () => queryFn(queryKey, queryFnArgs) }, options)); + return rqUseQuery(Object.assign({ queryKey: makeQueryCacheKey(query, queryFnArgs), queryFn: () => query(queryFnArgs) }, options)); } // PUBLIC API /** @@ -168,4 +166,4 @@ function getRqQueryKeyFromSpecifier(querySpecifier) { const [queryFn, ...otherKeys] = querySpecifier; return [...queryFn.queryCacheKey, ...otherKeys]; } -//# sourceMappingURL=core.js.map \ No newline at end of file +//# sourceMappingURL=hooks.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map new file mode 100644 index 0000000000..9048c71ee2 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../client/operations/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,WAAW,EAEX,cAAc,EACd,QAAQ,IAAI,UAAU,GAEvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAErD,aAAa;AACb,MAAM,UAAU,QAAQ,CACtB,KAA2B,EAC3B,WAAmB,EACnB,OAAa;IAEb,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAA;IACpE,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QACzB,MAAM,IAAI,SAAS,CAAC,uDAAuD,CAAC,CAAA;IAC9E,CAAC;IAED,OAAO,UAAU,iBACf,QAAQ,EAAE,iBAAiB,CAAC,KAAK,EAAE,WAAW,CAAC,EAC/C,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,IAC9B,OAAO,EACV,CAAA;AACJ,CAAC;AAED,aAAa;AACb;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CACvB,QAA+B,EAC/B,aAAoC;IAEpC,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IAErC,IAAI,UAAU,GAAG,QAAQ,CAAC;IAC1B,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,iBAAiB,EAAE,CAAC;QACrC,MAAM,4BAA4B,GAAG,aAAa,CAAC,iBAAiB,CAAC,GAAG,CACtE,6BAA6B,CAC9B,CAAC;QACF,UAAU,GAAG,8BAA8B,CACzC,QAAQ,EACR,4BAA4B,CAC7B,CAAC;QACF,OAAO,GAAG,6BAA6B,CACrC,WAAW,EACX,4BAA4B,CAC7B,CAAC;IACJ,CAAC;IAED,wEAAwE;IACxE,2EAA2E;IAC3E,wEAAwE;IACxE,4EAA4E;IAC5E,4EAA4E;IAC5E,sEAAsE;IACtE,0CAA0C;IAC1C,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AA2ED;;;;;;;;GAQG;AACH,SAAS,6BAA6B,CACpC,gCAA8E;IAE9E,MAAM,EAAE,iBAAiB,EAAE,WAAW,EAAE,GAAG,gCAAgC,CAAC;IAE5E,MAAM,gBAAgB,GAAG,EAAE,CAAC;IAC5B,IAAI,OAAO,iBAAiB,KAAK,UAAU,EAAE,CAAC;QAC5C,gBAAgB,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,OAAO,WAAW,KAAK,UAAU,EAAE,CAAC;QACtC,gBAAgB,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,gBAAgB,CAAC,MAAM,EAAE,CAAC;QAC5B,MAAM,IAAI,SAAS,CACjB,yCAAyC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACxE,CAAC;IACJ,CAAC;IAED,OAAO;QACL,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,0BAA0B,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC1E,WAAW;KACZ,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,8BAA8B,CACrC,QAA+B,EAC/B,2BAGG;IAEH,OAAO,SAAS,kCAAkC,CAAC,IAAI;QACrD,MAAM,mCAAmC,GAAG,2BAA2B,CAAC,GAAG,CACzE,CAAC,iBAAiB,EAAE,EAAE,CACpB,4CAA4C,CAAC,iBAAiB,EAAE,IAAI,CAAC,CACxE,CAAC;QACF,OAAQ,QAA0C,CAAC,QAAQ,CACzD,IAAI,EACJ,mCAAmC,CACpC,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,SAAS,6BAA6B,CACpC,WAAwB,EACxB,2BAGG;IAEH,KAAK,UAAU,QAAQ,CAAC,IAAI;QAC1B,MAAM,mCAAmC,GAAG,2BAA2B,CAAC,GAAG,CACzE,CAAC,iBAAiB,EAAE,EAAE,CACpB,4CAA4C,CAAC,iBAAiB,EAAE,IAAI,CAAC,CACxE,CAAC;QAEF,iFAAiF;QACjF,iEAAiE;QACjE,4EAA4E;QAC5E,mFAAmF;QACnF,MAAM,OAAO,CAAC,GAAG,CACf,mCAAmC,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CACvD,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CACpC,CACF,CAAC;QAEF,4EAA4E;QAC5E,MAAM,YAAY,GAAG,IAAI,GAAG,EAAE,CAAC;QAC/B,mCAAmC,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE;YACxE,uCAAuC;YACvC,MAAM,oBAAoB,GACxB,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YAErC,kEAAkE;YAClE,IAAI,CAAC;gBACH,WAAW,CAAC,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;YAClD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CACX,4EAA4E,CAC7E,CAAC;gBACF,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACnB,CAAC;YAED,iEAAiE;YACjE,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,oBAAoB,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;QAEH,OAAO,EAAE,YAAY,EAAE,CAAC;IAC1B,CAAC;IAED,SAAS,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO;QACnC,+EAA+E;QAC/E,8EAA8E;QAC9E,8EAA8E;QAC9E,+EAA+E;QAC/E,YAAY;QACZ,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YACpD,MAAM,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAC1C,WAAW,CAAC,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,QAAQ;QACR,OAAO;KACR,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,4CAA4C,CACnD,0BAGC,EACD,IAAiB;IAEjB,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,0BAA0B,CAAC;IAChE,OAAO;QACL,QAAQ,EAAE,WAAW,CAAC,IAAI,CAAC;QAC3B,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,0BAA0B,CACjC,cAAgD;IAEhD,MAAM,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,GAAG,cAAc,CAAC;IAC/C,OAAO,CAAC,GAAI,OAAe,CAAC,aAAa,EAAE,GAAG,SAAS,CAAC,CAAC;AAC3D,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts index 301165fa8e..76ad094f0d 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts @@ -1,4 +1,4 @@ export * from './actions'; export * from './queries'; -export { useAction, useQuery, type OptimisticUpdateDefinition, } from './core'; +export { useAction, useQuery, type OptimisticUpdateDefinition, } from './hooks'; export { configureQueryClient, initializeQueryClient, queryClientInitialized } from './queryClient'; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js index f83307c7b1..fd2c6b29b0 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js @@ -6,7 +6,7 @@ export { // PUBLIC API useAction, // PUBLIC API -useQuery, } from './core'; +useQuery, } from './hooks'; export { // PUBLIC API configureQueryClient, diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js.map index 982c957a9a..a6cf9161ab 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,QAAQ,CAAA;AAEf,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,SAAS,CAAA;AAEhB,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts index 93bbd1ddaa..c70de80ba6 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts @@ -1,12 +1,25 @@ import { Route } from 'wasp/client'; -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Query } from '../core.js'; -export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; -export declare function addMetadataToQuery(query: (...args: any[]) => Promise, metadata: { - relativeQueryPath: string; +import type { GenericBackendOperation, GenericOperationRpc, OperationRpcFor, Query, QueryMetadata } from '../rpc.js'; +export declare function makeQueryCacheKey(query: Query, payload: Input): (string | Input)[]; +export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; +export declare function buildAndRegisterQuery(queryFn: QF, { queryCacheKey, queryRoute, entitiesUsed }: { + queryCacheKey: string[]; queryRoute: Route; entitiesUsed: string[]; -}): void; -export type QueryFor = Query[0], _Awaited<_ReturnType>>; -type GenericBackendQuery = (args: never, context: any) => unknown; +}): QueryForFunction; +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = QueryForFunction>; +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = OperationRpcFor; +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata; export {}; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js index c03f172443..fefdfc58fc 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js @@ -1,18 +1,28 @@ import { callOperation, makeOperationRoute } from '../internal/index.js'; import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources'; +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey(query, payload) { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey; +} +// PRIVATE API (unsed in SDK) export function createQuery(relativeQueryPath, entitiesUsed) { const queryRoute = makeOperationRoute(relativeQueryPath); - async function query(queryKey, queryArgs) { + const queryCacheKey = [relativeQueryPath]; + const queryFn = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs); - return getActiveOptimisticUpdates(queryKey).reduce((result, update) => update(result), serverResult); - } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }); - return query; + const queryCacheKey = makeQueryCacheKey(queryFn, queryArgs); + return getActiveOptimisticUpdates(queryCacheKey).reduce((result, update) => update(result), serverResult); + }; + return buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }); } -// PRIVATE API -export function addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) { - query.queryCacheKey = [relativeQueryPath]; +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }) { + const query = queryFn; + query.queryCacheKey = queryCacheKey; query.route = queryRoute; addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed); + return query; } //# sourceMappingURL=core.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map index dcc40d2693..0ef0547c44 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IAExD,KAAK,UAAU,KAAK,CAAC,QAAQ,EAAE,SAAS;QACtC,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,OAAO,0BAA0B,CAAC,QAAQ,CAAC,CAAC,MAAM,CAChD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAA;IAE1E,OAAO,KAAK,CAAA;AACd,CAAC;AAYD,cAAc;AACd,MAAM,UAAU,kBAAkB,CAChC,KAAK,EACL,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE;IAE/C,KAAK,CAAC,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IACzC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;AAC5D,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,gCAAgC;AAChC,MAAM,UAAU,iBAAiB,CAC/B,KAA2B,EAC3B,OAAc;IAEd,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC;QAC5B,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,aAAa,CAAA;AAC3B,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IACxD,MAAM,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAEzC,MAAM,OAAO,GAAmC,KAAK,EAAE,SAAS,EAAE,EAAE;QAClE,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,MAAM,aAAa,GAAG,iBAAiB,CAAC,OAAiC,EAAE,SAAS,CAAC,CAAA;QACrF,OAAO,0BAA0B,CAAC,aAAa,CAAC,CAAC,MAAM,CACrD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC,CAAA;IAED,OAAO,qBAAqB,CAC1B,OAAO,EACP,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,CAC5C,CAAA;AACH,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,qBAAqB,CACnC,OAAW,EACX,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAC6B;IAEtE,MAAM,KAAK,GAAG,OAA+B,CAAA;IAE7C,KAAK,CAAC,aAAa,GAAG,aAAa,CAAA;IACnC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IAE1D,OAAO,KAAK,CAAA;AACd,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts index 575c502be1..2d9dbafe81 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts @@ -1 +1 @@ -export { addMetadataToQuery } from './core'; +export { buildAndRegisterQuery } from './core'; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js index 1c28e8d0d3..56d2e15238 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js @@ -1,3 +1,3 @@ -// PRIVATE API -export { addMetadataToQuery } from './core'; +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map index 5c83611fa3..44416efcfa 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts new file mode 100644 index 0000000000..ee52ec65b4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts @@ -0,0 +1,38 @@ +import { type Route } from "wasp/client"; +import type { _Awaited, _ReturnType } from "wasp/universal/types"; +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata; +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation; +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation; +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[]; + route: Route; +}; +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = Parameters extends [] ? ClientOperation>> : ClientOperation[0], _Awaited<_ReturnType>>; +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown; +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise; +type ClientOperation = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export {}; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js new file mode 100644 index 0000000000..f3a500abe4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=rpc.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map new file mode 100644 index 0000000000..a51bf309e5 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../client/operations/rpc.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts index 645112861a..89fd0d7587 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts @@ -1,7 +1,7 @@ import { ReactElement } from 'react'; import { type SetupServer } from 'msw/node'; import { RenderResult } from '@testing-library/react'; -import { Query } from 'wasp/client/operations/core'; +import { Query } from 'wasp/client/operations/rpc'; import { Route } from 'wasp/client'; export type MockQuery = (query: Query, resJson: MockOutput) => void; export type MockApi = (route: Route, resJson: unknown) => void; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/package.json index e3a3bb5440..73e355a456 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/package.json @@ -41,7 +41,7 @@ "./client/auth": "./dist/client/auth/index.js", "./client/crud": "./dist/client/crud/index.js", "./client/operations": "./dist/client/operations/index.js", - "./client/operations/core": "./dist/client/operations/core.js", + "./client/operations/rpc": "./dist/client/operations/rpc.js", "./client/router": "./dist/client/router/index.js", "./client/test": "./dist/client/test/index.js", "./client/test/*": "./dist/client/test/*.js", diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/files.manifest b/waspc/e2e-test/test-outputs/waspCompile-golden/files.manifest index 2e7b362e07..2c13607caf 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/files.manifest +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/files.manifest @@ -9,7 +9,7 @@ waspCompile/.wasp/out/sdk/wasp/client/config.ts waspCompile/.wasp/out/sdk/wasp/client/index.ts waspCompile/.wasp/out/sdk/wasp/client/operations/actions/core.ts waspCompile/.wasp/out/sdk/wasp/client/operations/actions/index.ts -waspCompile/.wasp/out/sdk/wasp/client/operations/core.ts +waspCompile/.wasp/out/sdk/wasp/client/operations/hooks.ts waspCompile/.wasp/out/sdk/wasp/client/operations/index.ts waspCompile/.wasp/out/sdk/wasp/client/operations/internal/index.ts waspCompile/.wasp/out/sdk/wasp/client/operations/internal/resources.js @@ -17,6 +17,7 @@ waspCompile/.wasp/out/sdk/wasp/client/operations/internal/updateHandlersMap.js waspCompile/.wasp/out/sdk/wasp/client/operations/queries/core.ts waspCompile/.wasp/out/sdk/wasp/client/operations/queries/index.ts waspCompile/.wasp/out/sdk/wasp/client/operations/queryClient.ts +waspCompile/.wasp/out/sdk/wasp/client/operations/rpc.ts waspCompile/.wasp/out/sdk/wasp/client/router/Link.tsx waspCompile/.wasp/out/sdk/wasp/client/router/index.ts waspCompile/.wasp/out/sdk/wasp/client/router/linkHelpers.ts @@ -43,9 +44,9 @@ waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/index.d.ts waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js.map -waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts -waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js -waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts +waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js +waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -67,6 +68,9 @@ waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queryClient.d.ts waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts +waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js +waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map waspCompile/.wasp/out/sdk/wasp/dist/client/router/Link.d.ts waspCompile/.wasp/out/sdk/wasp/dist/client/router/Link.jsx waspCompile/.wasp/out/sdk/wasp/dist/client/router/Link.jsx.map diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums index 5643591dc4..b4f898e3bb 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/.waspchecksums @@ -32,7 +32,7 @@ "file", "../out/sdk/wasp/client/operations/actions/core.ts" ], - "016623c0ebdc1b88d746fa1345015b3cb9653429abdc13a9147a952bff83a927" + "d19dba04947e4015af69d90dd160ec5f4ed020bfa905bc37bcd5d980517097ae" ], [ [ @@ -44,16 +44,16 @@ [ [ "file", - "../out/sdk/wasp/client/operations/core.ts" + "../out/sdk/wasp/client/operations/hooks.ts" ], - "bad860771b16a0d4830fab22de8b85e63c840d47dc3728728a23b8ada91061ef" + "eb4362162aad4b605781e2e33facef83935a7df4101cc0a77097ceaff3a0b360" ], [ [ "file", "../out/sdk/wasp/client/operations/index.ts" ], - "4a66c90319dd7ef0d3a8e6c1f571037c7dfd9778b9def6e951813dbc4b4dcef3" + "edcdc3798590e62b778115b3818df8cc69fa5a8bb3a7fe9fa6d6d5ea706d14c4" ], [ [ @@ -81,14 +81,14 @@ "file", "../out/sdk/wasp/client/operations/queries/core.ts" ], - "5f30328d93582f9c8444720e99f45c19c8647f052b7fbcf5f71b578b9241ac96" + "cce982751b463494c048efd683dddb8d4e617d2f354722a79961199990c7201a" ], [ [ "file", "../out/sdk/wasp/client/operations/queries/index.ts" ], - "882410504b909cc421d50a27c39952f664ba3457438ce746a95d9cab3431944c" + "c92c64425986a38f835211c2693380a8b13904cb78bbf6f6ae880e56ade51686" ], [ [ @@ -97,6 +97,13 @@ ], "5c1d87ac10513788bcde7ebc7c10601b9ad0854cddff355e8fb7e2d4685ecdef" ], + [ + [ + "file", + "../out/sdk/wasp/client/operations/rpc.ts" + ], + "5ab471422e7916c33a0931ce8d499d7d40191802ce2c6f3343b45c623a963566" + ], [ [ "file", @@ -137,7 +144,7 @@ "file", "../out/sdk/wasp/client/test/vitest/helpers.tsx" ], - "b2362e8f80134137fda2f8bb43ef7c0d7ae8aadf8a7adfa472d42d6699e9d918" + "b44ff591a2eebfff4de9fa9e9e1b89f1f22f523f03ab0febc19ff3999721b39a" ], [ [ @@ -193,7 +200,7 @@ "file", "../out/sdk/wasp/package.json" ], - "3422dd87e9e5f4aeb3922ee152ad691399d91ad71172f2b76f6235eb28955fa2" + "8df2ebcc130b484aa956ddf0109b23c83fe2221cb41ea35ed5e99817013f36a9" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/actions/core.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/actions/core.ts index f5db25aff2..c24f726ef3 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/actions/core.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/actions/core.ts @@ -1,5 +1,5 @@ -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Action } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { registerActionInProgress, @@ -7,7 +7,7 @@ import { } from '../internal/resources.js' // PRIVATE API -export function createAction( +export function createAction( relativeActionRoute: string, entitiesUsed: unknown[] ): ActionFor { @@ -41,8 +41,5 @@ export function createAction( } // PRIVATE API -export type ActionFor = - Action[0], _Awaited<_ReturnType>> - - -type GenericBackendAction = (args: never, context: any) => unknown +export type ActionFor = + OperationRpcFor diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/core.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/hooks.ts similarity index 88% rename from waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/core.ts rename to waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/hooks.ts index 282c4698a7..fa913a44c1 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/core.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/hooks.ts @@ -7,91 +7,31 @@ import { useQuery as rqUseQuery, UseQueryResult, } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; +import { makeQueryCacheKey } from "./queries/core"; export { configureQueryClient } from "./queryClient"; -// PRIVATE API (but should maybe be public, users use values of this type) -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; - // PUBLIC API export function useQuery( - queryFn: Query, + query: Query, queryFnArgs?: Input, options?: any -): UseQueryResult; - -// PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); +): UseQueryResult { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.') } - if (!queryFn.queryCacheKey) { - throw new TypeError( - "queryFn needs to have queryCacheKey property defined." - ); + + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.') } - const queryKey = - queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; return rqUseQuery({ - queryKey, - queryFn: () => queryFn(queryKey, queryFnArgs), + queryKey: makeQueryCacheKey(query, queryFnArgs), + queryFn: () => query(queryFnArgs), ...options, - }); + }) } -// PRIVATE API (but should maybe be public, users use values of this type) -export type Action = [Input] extends [never] - ? (args?: unknown) => Promise - : (args: Input) => Promise; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. - * - */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; - -// PUBLIC API -/** - * A documented (public) way to define optimistic updates. - */ -export type OptimisticUpdateDefinition = { - getQuerySpecifier: GetQuerySpecifier; - updateQuery: UpdateQuery; -}; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and returns a Wasp Query specifier. - */ -export type GetQuerySpecifier = ( - item: ActionInput -) => QuerySpecifier; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and the previous state of the cache, and returns - * the desired (new) state of the cache. - */ -export type UpdateQuery = ( - item: ActionInput, - oldData: CachedData | undefined -) => CachedData; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A public query specifier used for addressing Wasp queries. See our docs for details: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - */ -export type QuerySpecifier = [Query, ...any[]]; - // PUBLIC API /** * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). @@ -133,6 +73,48 @@ export function useAction( return (args) => mutation.mutateAsync(args); } +// PUBLIC API +/** + * A documented (public) way to define optimistic updates. + */ +export type OptimisticUpdateDefinition = { + getQuerySpecifier: GetQuerySpecifier; + updateQuery: UpdateQuery; +}; + +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; + +/** + * A function that takes an item and returns a Wasp Query specifier. + */ +type GetQuerySpecifier = ( + item: ActionInput +) => QuerySpecifier; + +/** + * A function that takes an item and the previous state of the cache, and returns + * the desired (new) state of the cache. + */ +type UpdateQuery = ( + item: ActionInput, + oldData: CachedData | undefined +) => CachedData; + +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * A public query specifier used for addressing Wasp queries. See our docs for details: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + */ +type QuerySpecifier = [Query, ...any[]]; + + /** * An internal (undocumented, private, desugared) way of defining optimistic updates. */ diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/index.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/index.ts index ec9ca9f689..4dc2691035 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/index.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/index.ts @@ -10,7 +10,7 @@ export { useQuery, // PUBLIC API type OptimisticUpdateDefinition, -} from './core' +} from './hooks' export { // PUBLIC API diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/queries/core.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/queries/core.ts index bdc0a9db75..36cd6ad067 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/queries/core.ts @@ -1,53 +1,83 @@ import { Route } from 'wasp/client' -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Query } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { + GenericBackendOperation, + GenericOperationRpc, + OperationRpcFor, + Query, + QueryMetadata, +} from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources' -export function createQuery( +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey( + query: Query, + payload: Input +): (string | Input)[] { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey +} + +// PRIVATE API (unsed in SDK) +export function createQuery( relativeQueryPath: string, entitiesUsed: string[] ): QueryFor { const queryRoute = makeOperationRoute(relativeQueryPath) + const queryCacheKey = [relativeQueryPath] - async function query(queryKey, queryArgs) { + const queryFn: QueryFunctionFor = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) - return getActiveOptimisticUpdates(queryKey).reduce( + const queryCacheKey = makeQueryCacheKey(queryFn as QueryFor, queryArgs) + return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), serverResult, ) } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) - - return query + return buildAndRegisterQuery( + queryFn, + { queryCacheKey, queryRoute, entitiesUsed }, + ) } -// PRIVATE API -export function addMetadataToQuery( - query: (...args: any[]) => Promise, - metadata: { - relativeQueryPath: string - queryRoute: Route - entitiesUsed: string[] - } -): void - -// PRIVATE API -export function addMetadataToQuery( - query, - { relativeQueryPath, queryRoute, entitiesUsed } -) { - query.queryCacheKey = [relativeQueryPath] +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery( + queryFn: QF, + { queryCacheKey, queryRoute, entitiesUsed }: + { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } +): QueryForFunction { + const query = queryFn as QueryForFunction + + query.queryCacheKey = queryCacheKey query.route = queryRoute addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) + + return query } -export type QueryFor = - Query[0], _Awaited<_ReturnType>> +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = + QueryForFunction> +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = + OperationRpcFor -type GenericBackendQuery = (args: never, context: any) => unknown \ No newline at end of file +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/queries/index.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/queries/index.ts index eeb2cf5a11..af63c67c63 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/queries/index.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/queries/index.ts @@ -1,4 +1,4 @@ import { type QueryFor, createQuery } from './core' -// PRIVATE API -export { addMetadataToQuery } from './core' +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core' diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/rpc.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/rpc.ts new file mode 100644 index 0000000000..45a8dbbf47 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/operations/rpc.ts @@ -0,0 +1,77 @@ +import { type Route } from "wasp/client"; +import type { + _Awaited, + _ReturnType, +} from "wasp/universal/types" + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type). +// +// Frontend queries are functions with some extra properties (metadata). +// +// To simplify working with the type (i.e., referencing the type's two different +// components), we've defined it as an intersection of two distinct types: +// one representing the function (QueryFunction), and the other representing the +// metadata (QueryMetadata) . +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type) +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation + +// PRIVATE API (for SDK) +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation + +// PRIVATE API (for SDK) +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[] + route: Route +} + +// PRIVATE API (needed in SDK) +// Explanation: +// - Custom `_Awaited` and `_ReturnType` - Read the comments above their +// definitions. +// - `Parameters extends []` - See here: +// https://github.com/wasp-lang/wasp/pull/1992/files#r1583040080 +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = + Parameters extends [] + ? ClientOperation>> + : ClientOperation< + Parameters[0], + _Awaited<_ReturnType> + > + +// PRIVATE API (needed in SDK) +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown + +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise + +// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 +type ClientOperation = [Input] extends [never] + ? (args?: unknown) => Promise + : (args: Input) => Promise; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx index 8e6085f34c..96ff5e90e8 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx @@ -6,7 +6,7 @@ import { BrowserRouter as Router } from 'react-router-dom' import { render, RenderResult, cleanup } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { beforeAll, afterEach, afterAll } from 'vitest' -import { Query } from 'wasp/client/operations/core' +import { Query } from 'wasp/client/operations/rpc' import { config } from 'wasp/client' import { HttpMethod, Route } from 'wasp/client' diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts index e1708451f8..4b8c455fd4 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts @@ -1,6 +1,3 @@ -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Action } from '../core.js'; -export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; -export type ActionFor = Action[0], _Awaited<_ReturnType>>; -type GenericBackendAction = (args: never, context: any) => unknown; -export {}; +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js'; +export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; +export type ActionFor = OperationRpcFor; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js.map deleted file mode 100644 index 20d72dc15e..0000000000 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts similarity index 65% rename from waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts rename to waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts index a23b24ebd6..36a5e0b65b 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts @@ -1,18 +1,15 @@ import { UseQueryResult } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; export { configureQueryClient } from "./queryClient"; -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; -export declare function useQuery(queryFn: Query, queryFnArgs?: Input, options?: any): UseQueryResult; -export type Action = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export declare function useQuery(query: Query, queryFnArgs?: Input, options?: any): UseQueryResult; /** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; +export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; /** * A documented (public) way to define optimistic updates. */ @@ -20,25 +17,25 @@ export type OptimisticUpdateDefinition = { getQuerySpecifier: GetQuerySpecifier; updateQuery: UpdateQuery; }; +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; /** * A function that takes an item and returns a Wasp Query specifier. */ -export type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; +type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; /** * A function that takes an item and the previous state of the cache, and returns * the desired (new) state of the cache. */ -export type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; +type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; /** * A public query specifier used for addressing Wasp queries. See our docs for details: * https://wasp-lang.dev/docs/language/features#the-useaction-hook. */ -export type QuerySpecifier = [Query, ...any[]]; -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; +type QuerySpecifier = [Query, ...any[]]; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js similarity index 93% rename from waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js rename to waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js index 2c94cb01fd..95ab379515 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/build/sdk/wasp/dist/client/operations/core.js +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js @@ -1,17 +1,15 @@ import { useMutation, useQueryClient, useQuery as rqUseQuery, } from "@tanstack/react-query"; +import { makeQueryCacheKey } from "./queries/core"; export { configureQueryClient } from "./queryClient"; // PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); +export function useQuery(query, queryFnArgs, options) { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.'); } - if (!queryFn.queryCacheKey) { - throw new TypeError("queryFn needs to have queryCacheKey property defined."); + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.'); } - const queryKey = queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; - return rqUseQuery(Object.assign({ queryKey, queryFn: () => queryFn(queryKey, queryFnArgs) }, options)); + return rqUseQuery(Object.assign({ queryKey: makeQueryCacheKey(query, queryFnArgs), queryFn: () => query(queryFnArgs) }, options)); } // PUBLIC API /** @@ -168,4 +166,4 @@ function getRqQueryKeyFromSpecifier(querySpecifier) { const [queryFn, ...otherKeys] = querySpecifier; return [...queryFn.queryCacheKey, ...otherKeys]; } -//# sourceMappingURL=core.js.map \ No newline at end of file +//# sourceMappingURL=hooks.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map new file mode 100644 index 0000000000..9048c71ee2 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../client/operations/hooks.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts index 301165fa8e..76ad094f0d 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts @@ -1,4 +1,4 @@ export * from './actions'; export * from './queries'; -export { useAction, useQuery, type OptimisticUpdateDefinition, } from './core'; +export { useAction, useQuery, type OptimisticUpdateDefinition, } from './hooks'; export { configureQueryClient, initializeQueryClient, queryClientInitialized } from './queryClient'; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js index f83307c7b1..fd2c6b29b0 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js @@ -6,7 +6,7 @@ export { // PUBLIC API useAction, // PUBLIC API -useQuery, } from './core'; +useQuery, } from './hooks'; export { // PUBLIC API configureQueryClient, diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js.map index 982c957a9a..a6cf9161ab 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,QAAQ,CAAA;AAEf,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,SAAS,CAAA;AAEhB,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts index 93bbd1ddaa..c70de80ba6 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts @@ -1,12 +1,25 @@ import { Route } from 'wasp/client'; -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Query } from '../core.js'; -export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; -export declare function addMetadataToQuery(query: (...args: any[]) => Promise, metadata: { - relativeQueryPath: string; +import type { GenericBackendOperation, GenericOperationRpc, OperationRpcFor, Query, QueryMetadata } from '../rpc.js'; +export declare function makeQueryCacheKey(query: Query, payload: Input): (string | Input)[]; +export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; +export declare function buildAndRegisterQuery(queryFn: QF, { queryCacheKey, queryRoute, entitiesUsed }: { + queryCacheKey: string[]; queryRoute: Route; entitiesUsed: string[]; -}): void; -export type QueryFor = Query[0], _Awaited<_ReturnType>>; -type GenericBackendQuery = (args: never, context: any) => unknown; +}): QueryForFunction; +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = QueryForFunction>; +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = OperationRpcFor; +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata; export {}; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js index c03f172443..fefdfc58fc 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js @@ -1,18 +1,28 @@ import { callOperation, makeOperationRoute } from '../internal/index.js'; import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources'; +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey(query, payload) { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey; +} +// PRIVATE API (unsed in SDK) export function createQuery(relativeQueryPath, entitiesUsed) { const queryRoute = makeOperationRoute(relativeQueryPath); - async function query(queryKey, queryArgs) { + const queryCacheKey = [relativeQueryPath]; + const queryFn = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs); - return getActiveOptimisticUpdates(queryKey).reduce((result, update) => update(result), serverResult); - } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }); - return query; + const queryCacheKey = makeQueryCacheKey(queryFn, queryArgs); + return getActiveOptimisticUpdates(queryCacheKey).reduce((result, update) => update(result), serverResult); + }; + return buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }); } -// PRIVATE API -export function addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) { - query.queryCacheKey = [relativeQueryPath]; +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }) { + const query = queryFn; + query.queryCacheKey = queryCacheKey; query.route = queryRoute; addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed); + return query; } //# sourceMappingURL=core.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map index dcc40d2693..0ef0547c44 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IAExD,KAAK,UAAU,KAAK,CAAC,QAAQ,EAAE,SAAS;QACtC,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,OAAO,0BAA0B,CAAC,QAAQ,CAAC,CAAC,MAAM,CAChD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAA;IAE1E,OAAO,KAAK,CAAA;AACd,CAAC;AAYD,cAAc;AACd,MAAM,UAAU,kBAAkB,CAChC,KAAK,EACL,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE;IAE/C,KAAK,CAAC,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IACzC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;AAC5D,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,gCAAgC;AAChC,MAAM,UAAU,iBAAiB,CAC/B,KAA2B,EAC3B,OAAc;IAEd,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC;QAC5B,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,aAAa,CAAA;AAC3B,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IACxD,MAAM,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAEzC,MAAM,OAAO,GAAmC,KAAK,EAAE,SAAS,EAAE,EAAE;QAClE,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,MAAM,aAAa,GAAG,iBAAiB,CAAC,OAAiC,EAAE,SAAS,CAAC,CAAA;QACrF,OAAO,0BAA0B,CAAC,aAAa,CAAC,CAAC,MAAM,CACrD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC,CAAA;IAED,OAAO,qBAAqB,CAC1B,OAAO,EACP,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,CAC5C,CAAA;AACH,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,qBAAqB,CACnC,OAAW,EACX,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAC6B;IAEtE,MAAM,KAAK,GAAG,OAA+B,CAAA;IAE7C,KAAK,CAAC,aAAa,GAAG,aAAa,CAAA;IACnC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IAE1D,OAAO,KAAK,CAAA;AACd,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts index 575c502be1..2d9dbafe81 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts @@ -1 +1 @@ -export { addMetadataToQuery } from './core'; +export { buildAndRegisterQuery } from './core'; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js index 1c28e8d0d3..56d2e15238 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js @@ -1,3 +1,3 @@ -// PRIVATE API -export { addMetadataToQuery } from './core'; +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map index 5c83611fa3..44416efcfa 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts new file mode 100644 index 0000000000..ee52ec65b4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts @@ -0,0 +1,38 @@ +import { type Route } from "wasp/client"; +import type { _Awaited, _ReturnType } from "wasp/universal/types"; +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata; +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation; +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation; +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[]; + route: Route; +}; +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = Parameters extends [] ? ClientOperation>> : ClientOperation[0], _Awaited<_ReturnType>>; +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown; +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise; +type ClientOperation = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export {}; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js new file mode 100644 index 0000000000..f3a500abe4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=rpc.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map new file mode 100644 index 0000000000..a51bf309e5 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../client/operations/rpc.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts index 645112861a..89fd0d7587 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts @@ -1,7 +1,7 @@ import { ReactElement } from 'react'; import { type SetupServer } from 'msw/node'; import { RenderResult } from '@testing-library/react'; -import { Query } from 'wasp/client/operations/core'; +import { Query } from 'wasp/client/operations/rpc'; import { Route } from 'wasp/client'; export type MockQuery = (query: Query, resJson: MockOutput) => void; export type MockApi = (route: Route, resJson: unknown) => void; diff --git a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/package.json index e3a3bb5440..73e355a456 100644 --- a/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspCompile-golden/waspCompile/.wasp/out/sdk/wasp/package.json @@ -41,7 +41,7 @@ "./client/auth": "./dist/client/auth/index.js", "./client/crud": "./dist/client/crud/index.js", "./client/operations": "./dist/client/operations/index.js", - "./client/operations/core": "./dist/client/operations/core.js", + "./client/operations/rpc": "./dist/client/operations/rpc.js", "./client/router": "./dist/client/router/index.js", "./client/test": "./dist/client/test/index.js", "./client/test/*": "./dist/client/test/*.js", diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/files.manifest b/waspc/e2e-test/test-outputs/waspComplexTest-golden/files.manifest index 24a71324bf..d712f5bad4 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/files.manifest +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/files.manifest @@ -39,7 +39,7 @@ waspComplexTest/.wasp/out/sdk/wasp/client/crud/tasks.ts waspComplexTest/.wasp/out/sdk/wasp/client/index.ts waspComplexTest/.wasp/out/sdk/wasp/client/operations/actions/core.ts waspComplexTest/.wasp/out/sdk/wasp/client/operations/actions/index.ts -waspComplexTest/.wasp/out/sdk/wasp/client/operations/core.ts +waspComplexTest/.wasp/out/sdk/wasp/client/operations/hooks.ts waspComplexTest/.wasp/out/sdk/wasp/client/operations/index.ts waspComplexTest/.wasp/out/sdk/wasp/client/operations/internal/index.ts waspComplexTest/.wasp/out/sdk/wasp/client/operations/internal/resources.js @@ -47,6 +47,7 @@ waspComplexTest/.wasp/out/sdk/wasp/client/operations/internal/updateHandlersMap. waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/core.ts waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/index.ts waspComplexTest/.wasp/out/sdk/wasp/client/operations/queryClient.ts +waspComplexTest/.wasp/out/sdk/wasp/client/operations/rpc.ts waspComplexTest/.wasp/out/sdk/wasp/client/router/Link.tsx waspComplexTest/.wasp/out/sdk/wasp/client/router/index.ts waspComplexTest/.wasp/out/sdk/wasp/client/router/linkHelpers.ts @@ -159,9 +160,9 @@ waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/index.d.ts waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js.map -waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts -waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js -waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts +waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js +waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -183,6 +184,9 @@ waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queryClient.d.ts waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts +waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js +waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map waspComplexTest/.wasp/out/sdk/wasp/dist/client/router/Link.d.ts waspComplexTest/.wasp/out/sdk/wasp/dist/client/router/Link.jsx waspComplexTest/.wasp/out/sdk/wasp/dist/client/router/Link.jsx.map diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums index 9b8b81d3a5..e43cec73d4 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/.waspchecksums @@ -151,7 +151,7 @@ "file", "../out/sdk/wasp/auth/useAuth.ts" ], - "2fc317b5939816da10ae7709768c4dae52f541aa274620c1896c9d423b0c3122" + "1d3aa0dd013b1f8be09601df62a462a4b22cd686e82e1c3d16e752a264008431" ], [ [ @@ -228,7 +228,7 @@ "file", "../out/sdk/wasp/client/operations/actions/core.ts" ], - "016623c0ebdc1b88d746fa1345015b3cb9653429abdc13a9147a952bff83a927" + "d19dba04947e4015af69d90dd160ec5f4ed020bfa905bc37bcd5d980517097ae" ], [ [ @@ -240,16 +240,16 @@ [ [ "file", - "../out/sdk/wasp/client/operations/core.ts" + "../out/sdk/wasp/client/operations/hooks.ts" ], - "bad860771b16a0d4830fab22de8b85e63c840d47dc3728728a23b8ada91061ef" + "eb4362162aad4b605781e2e33facef83935a7df4101cc0a77097ceaff3a0b360" ], [ [ "file", "../out/sdk/wasp/client/operations/index.ts" ], - "4a66c90319dd7ef0d3a8e6c1f571037c7dfd9778b9def6e951813dbc4b4dcef3" + "edcdc3798590e62b778115b3818df8cc69fa5a8bb3a7fe9fa6d6d5ea706d14c4" ], [ [ @@ -277,14 +277,14 @@ "file", "../out/sdk/wasp/client/operations/queries/core.ts" ], - "5f30328d93582f9c8444720e99f45c19c8647f052b7fbcf5f71b578b9241ac96" + "cce982751b463494c048efd683dddb8d4e617d2f354722a79961199990c7201a" ], [ [ "file", "../out/sdk/wasp/client/operations/queries/index.ts" ], - "0f9a37061deb021b9532f4601be54e244067dcf1c39b0d47db92f2d1e1c59c78" + "f086e3b7f43d3b4fdd7b8a4e32907d245b4cddf837c7f777b07fc1d3577c067c" ], [ [ @@ -293,6 +293,13 @@ ], "5c1d87ac10513788bcde7ebc7c10601b9ad0854cddff355e8fb7e2d4685ecdef" ], + [ + [ + "file", + "../out/sdk/wasp/client/operations/rpc.ts" + ], + "5ab471422e7916c33a0931ce8d499d7d40191802ce2c6f3343b45c623a963566" + ], [ [ "file", @@ -333,7 +340,7 @@ "file", "../out/sdk/wasp/client/test/vitest/helpers.tsx" ], - "b2362e8f80134137fda2f8bb43ef7c0d7ae8aadf8a7adfa472d42d6699e9d918" + "b44ff591a2eebfff4de9fa9e9e1b89f1f22f523f03ab0febc19ff3999721b39a" ], [ [ @@ -466,7 +473,7 @@ "file", "../out/sdk/wasp/package.json" ], - "0f0265981290d0585a53f8fb24e8e37f41e0e89c8379efce5334a51197548c93" + "75c4ac6e306ef6d0e017dc778ba2c5febe9fea168c3ecf03f80c5086c4e35054" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/useAuth.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/useAuth.ts index 4e34972e19..f2995f5424 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/useAuth.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/auth/useAuth.ts @@ -1,22 +1,23 @@ import { deserialize as superjsonDeserialize } from 'superjson' -import { useQuery, addMetadataToQuery } from 'wasp/client/operations' +import { useQuery, buildAndRegisterQuery } from 'wasp/client/operations' +import type { QueryFunction, Query } from 'wasp/client/operations/rpc' import { api, handleApiError } from 'wasp/client/api' import { HttpMethod } from 'wasp/client' import type { AuthUser } from '../server/auth/user.js' import { UseQueryResult } from '@tanstack/react-query' // PUBLIC API -export const getMe: () => Promise = createUserGetter() +export const getMe: Query = createUserGetter() // PUBLIC API -export default function useAuth(queryFnArgs?: unknown, config?: any): UseQueryResult { - return useQuery(getMe, queryFnArgs, config) -} +export default function useAuth(): UseQueryResult { + return useQuery(getMe) +} -function createUserGetter() { +function createUserGetter(): Query { const getMeRelativePath = 'auth/me' const getMeRoute = { method: HttpMethod.Get, path: `/${getMeRelativePath}` } - async function getMe(): Promise { + const getMe: QueryFunction = async () => { try { const response = await api.get(getMeRoute.path) @@ -30,11 +31,9 @@ function createUserGetter() { } } - addMetadataToQuery(getMe, { - relativeQueryPath: getMeRelativePath, + return buildAndRegisterQuery(getMe, { + queryCacheKey: [getMeRelativePath], queryRoute: getMeRoute, entitiesUsed: ['User'], }) - - return getMe } diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/actions/core.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/actions/core.ts index f5db25aff2..c24f726ef3 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/actions/core.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/actions/core.ts @@ -1,5 +1,5 @@ -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Action } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { registerActionInProgress, @@ -7,7 +7,7 @@ import { } from '../internal/resources.js' // PRIVATE API -export function createAction( +export function createAction( relativeActionRoute: string, entitiesUsed: unknown[] ): ActionFor { @@ -41,8 +41,5 @@ export function createAction( } // PRIVATE API -export type ActionFor = - Action[0], _Awaited<_ReturnType>> - - -type GenericBackendAction = (args: never, context: any) => unknown +export type ActionFor = + OperationRpcFor diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/core.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/hooks.ts similarity index 88% rename from waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/core.ts rename to waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/hooks.ts index 282c4698a7..fa913a44c1 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/core.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/hooks.ts @@ -7,91 +7,31 @@ import { useQuery as rqUseQuery, UseQueryResult, } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; +import { makeQueryCacheKey } from "./queries/core"; export { configureQueryClient } from "./queryClient"; -// PRIVATE API (but should maybe be public, users use values of this type) -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; - // PUBLIC API export function useQuery( - queryFn: Query, + query: Query, queryFnArgs?: Input, options?: any -): UseQueryResult; - -// PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); +): UseQueryResult { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.') } - if (!queryFn.queryCacheKey) { - throw new TypeError( - "queryFn needs to have queryCacheKey property defined." - ); + + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.') } - const queryKey = - queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; return rqUseQuery({ - queryKey, - queryFn: () => queryFn(queryKey, queryFnArgs), + queryKey: makeQueryCacheKey(query, queryFnArgs), + queryFn: () => query(queryFnArgs), ...options, - }); + }) } -// PRIVATE API (but should maybe be public, users use values of this type) -export type Action = [Input] extends [never] - ? (args?: unknown) => Promise - : (args: Input) => Promise; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. - * - */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; - -// PUBLIC API -/** - * A documented (public) way to define optimistic updates. - */ -export type OptimisticUpdateDefinition = { - getQuerySpecifier: GetQuerySpecifier; - updateQuery: UpdateQuery; -}; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and returns a Wasp Query specifier. - */ -export type GetQuerySpecifier = ( - item: ActionInput -) => QuerySpecifier; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and the previous state of the cache, and returns - * the desired (new) state of the cache. - */ -export type UpdateQuery = ( - item: ActionInput, - oldData: CachedData | undefined -) => CachedData; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A public query specifier used for addressing Wasp queries. See our docs for details: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - */ -export type QuerySpecifier = [Query, ...any[]]; - // PUBLIC API /** * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). @@ -133,6 +73,48 @@ export function useAction( return (args) => mutation.mutateAsync(args); } +// PUBLIC API +/** + * A documented (public) way to define optimistic updates. + */ +export type OptimisticUpdateDefinition = { + getQuerySpecifier: GetQuerySpecifier; + updateQuery: UpdateQuery; +}; + +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; + +/** + * A function that takes an item and returns a Wasp Query specifier. + */ +type GetQuerySpecifier = ( + item: ActionInput +) => QuerySpecifier; + +/** + * A function that takes an item and the previous state of the cache, and returns + * the desired (new) state of the cache. + */ +type UpdateQuery = ( + item: ActionInput, + oldData: CachedData | undefined +) => CachedData; + +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * A public query specifier used for addressing Wasp queries. See our docs for details: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + */ +type QuerySpecifier = [Query, ...any[]]; + + /** * An internal (undocumented, private, desugared) way of defining optimistic updates. */ diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/index.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/index.ts index ec9ca9f689..4dc2691035 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/index.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/index.ts @@ -10,7 +10,7 @@ export { useQuery, // PUBLIC API type OptimisticUpdateDefinition, -} from './core' +} from './hooks' export { // PUBLIC API diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/core.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/core.ts index bdc0a9db75..36cd6ad067 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/core.ts @@ -1,53 +1,83 @@ import { Route } from 'wasp/client' -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Query } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { + GenericBackendOperation, + GenericOperationRpc, + OperationRpcFor, + Query, + QueryMetadata, +} from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources' -export function createQuery( +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey( + query: Query, + payload: Input +): (string | Input)[] { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey +} + +// PRIVATE API (unsed in SDK) +export function createQuery( relativeQueryPath: string, entitiesUsed: string[] ): QueryFor { const queryRoute = makeOperationRoute(relativeQueryPath) + const queryCacheKey = [relativeQueryPath] - async function query(queryKey, queryArgs) { + const queryFn: QueryFunctionFor = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) - return getActiveOptimisticUpdates(queryKey).reduce( + const queryCacheKey = makeQueryCacheKey(queryFn as QueryFor, queryArgs) + return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), serverResult, ) } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) - - return query + return buildAndRegisterQuery( + queryFn, + { queryCacheKey, queryRoute, entitiesUsed }, + ) } -// PRIVATE API -export function addMetadataToQuery( - query: (...args: any[]) => Promise, - metadata: { - relativeQueryPath: string - queryRoute: Route - entitiesUsed: string[] - } -): void - -// PRIVATE API -export function addMetadataToQuery( - query, - { relativeQueryPath, queryRoute, entitiesUsed } -) { - query.queryCacheKey = [relativeQueryPath] +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery( + queryFn: QF, + { queryCacheKey, queryRoute, entitiesUsed }: + { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } +): QueryForFunction { + const query = queryFn as QueryForFunction + + query.queryCacheKey = queryCacheKey query.route = queryRoute addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) + + return query } -export type QueryFor = - Query[0], _Awaited<_ReturnType>> +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = + QueryForFunction> +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = + OperationRpcFor -type GenericBackendQuery = (args: never, context: any) => unknown \ No newline at end of file +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/index.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/index.ts index 7a7ad3e2e3..13dd534ed5 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/index.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/operations/queries/index.ts @@ -7,5 +7,5 @@ export const mySpecialQuery: QueryFor = createQuery = QueryFunction & QueryMetadata + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type) +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation + +// PRIVATE API (for SDK) +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation + +// PRIVATE API (for SDK) +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[] + route: Route +} + +// PRIVATE API (needed in SDK) +// Explanation: +// - Custom `_Awaited` and `_ReturnType` - Read the comments above their +// definitions. +// - `Parameters extends []` - See here: +// https://github.com/wasp-lang/wasp/pull/1992/files#r1583040080 +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = + Parameters extends [] + ? ClientOperation>> + : ClientOperation< + Parameters[0], + _Awaited<_ReturnType> + > + +// PRIVATE API (needed in SDK) +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown + +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise + +// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 +type ClientOperation = [Input] extends [never] + ? (args?: unknown) => Promise + : (args: Input) => Promise; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx index 8e6085f34c..96ff5e90e8 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx @@ -6,7 +6,7 @@ import { BrowserRouter as Router } from 'react-router-dom' import { render, RenderResult, cleanup } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { beforeAll, afterEach, afterAll } from 'vitest' -import { Query } from 'wasp/client/operations/core' +import { Query } from 'wasp/client/operations/rpc' import { config } from 'wasp/client' import { HttpMethod, Route } from 'wasp/client' diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.d.ts index 8cb868b58a..c1607701c3 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.d.ts @@ -1,4 +1,5 @@ +import type { Query } from 'wasp/client/operations/rpc'; import type { AuthUser } from '../server/auth/user.js'; import { UseQueryResult } from '@tanstack/react-query'; -export declare const getMe: () => Promise; -export default function useAuth(queryFnArgs?: unknown, config?: any): UseQueryResult; +export declare const getMe: Query; +export default function useAuth(): UseQueryResult; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js index 9029f7877f..f5789a25b0 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js @@ -1,17 +1,17 @@ import { deserialize as superjsonDeserialize } from 'superjson'; -import { useQuery, addMetadataToQuery } from 'wasp/client/operations'; +import { useQuery, buildAndRegisterQuery } from 'wasp/client/operations'; import { api, handleApiError } from 'wasp/client/api'; import { HttpMethod } from 'wasp/client'; // PUBLIC API export const getMe = createUserGetter(); // PUBLIC API -export default function useAuth(queryFnArgs, config) { - return useQuery(getMe, queryFnArgs, config); +export default function useAuth() { + return useQuery(getMe); } function createUserGetter() { const getMeRelativePath = 'auth/me'; const getMeRoute = { method: HttpMethod.Get, path: `/${getMeRelativePath}` }; - async function getMe() { + const getMe = async () => { var _a; try { const response = await api.get(getMeRoute.path); @@ -25,12 +25,11 @@ function createUserGetter() { handleApiError(error); } } - } - addMetadataToQuery(getMe, { - relativeQueryPath: getMeRelativePath, + }; + return buildAndRegisterQuery(getMe, { + queryCacheKey: [getMeRelativePath], queryRoute: getMeRoute, entitiesUsed: ['User'], }); - return getMe; } //# sourceMappingURL=useAuth.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js.map index f85abe5613..974c8d6dfa 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/auth/useAuth.js.map @@ -1 +1 @@ -{"version":3,"file":"useAuth.js","sourceRoot":"","sources":["../../auth/useAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AACrE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAIxC,aAAa;AACb,MAAM,CAAC,MAAM,KAAK,GAAmC,gBAAgB,EAAE,CAAA;AAEvE,aAAa;AACb,MAAM,CAAC,OAAO,UAAU,OAAO,CAAC,WAAqB,EAAE,MAAY;IACjE,OAAO,QAAQ,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;AAC7C,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,iBAAiB,GAAG,SAAS,CAAA;IACnC,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,iBAAiB,EAAE,EAAE,CAAA;IAC5E,KAAK,UAAU,KAAK;;QAClB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YAE/C,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC5C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAA,MAAA,KAAK,CAAC,QAAQ,0CAAE,MAAM,MAAK,GAAG,EAAE,CAAC;gBACnC,OAAO,IAAI,CAAA;YACb,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,KAAK,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE;QACxB,iBAAiB,EAAE,iBAAiB;QACpC,UAAU,EAAE,UAAU;QACtB,YAAY,EAAE,CAAC,MAAM,CAAC;KACvB,CAAC,CAAA;IAEF,OAAO,KAAK,CAAA;AACd,CAAC"} \ No newline at end of file +{"version":3,"file":"useAuth.js","sourceRoot":"","sources":["../../auth/useAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AAExE,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAIxC,aAAa;AACb,MAAM,CAAC,MAAM,KAAK,GAAiC,gBAAgB,EAAE,CAAA;AAErE,aAAa;AACb,MAAM,CAAC,OAAO,UAAU,OAAO;IAC7B,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAA;AACxB,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,iBAAiB,GAAG,SAAS,CAAA;IACnC,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,iBAAiB,EAAE,EAAE,CAAA;IAC5E,MAAM,KAAK,GAAyC,KAAK,IAAI,EAAE;;QAC7D,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YAE/C,OAAO,oBAAoB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QAC5C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAA,MAAA,KAAK,CAAC,QAAQ,0CAAE,MAAM,MAAK,GAAG,EAAE,CAAC;gBACnC,OAAO,IAAI,CAAA;YACb,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,KAAK,CAAC,CAAA;YACvB,CAAC;QACH,CAAC;IACH,CAAC,CAAA;IAED,OAAO,qBAAqB,CAAC,KAAK,EAAE;QAClC,aAAa,EAAE,CAAC,iBAAiB,CAAC;QAClC,UAAU,EAAE,UAAU;QACtB,YAAY,EAAE,CAAC,MAAM,CAAC;KACvB,CAAC,CAAA;AACJ,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts index e1708451f8..4b8c455fd4 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts @@ -1,6 +1,3 @@ -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Action } from '../core.js'; -export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; -export type ActionFor = Action[0], _Awaited<_ReturnType>>; -type GenericBackendAction = (args: never, context: any) => unknown; -export {}; +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js'; +export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; +export type ActionFor = OperationRpcFor; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js.map deleted file mode 100644 index 20d72dc15e..0000000000 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts similarity index 65% rename from waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts rename to waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts index a23b24ebd6..36a5e0b65b 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts @@ -1,18 +1,15 @@ import { UseQueryResult } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; export { configureQueryClient } from "./queryClient"; -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; -export declare function useQuery(queryFn: Query, queryFnArgs?: Input, options?: any): UseQueryResult; -export type Action = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export declare function useQuery(query: Query, queryFnArgs?: Input, options?: any): UseQueryResult; /** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; +export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; /** * A documented (public) way to define optimistic updates. */ @@ -20,25 +17,25 @@ export type OptimisticUpdateDefinition = { getQuerySpecifier: GetQuerySpecifier; updateQuery: UpdateQuery; }; +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; /** * A function that takes an item and returns a Wasp Query specifier. */ -export type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; +type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; /** * A function that takes an item and the previous state of the cache, and returns * the desired (new) state of the cache. */ -export type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; +type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; /** * A public query specifier used for addressing Wasp queries. See our docs for details: * https://wasp-lang.dev/docs/language/features#the-useaction-hook. */ -export type QuerySpecifier = [Query, ...any[]]; -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; +type QuerySpecifier = [Query, ...any[]]; diff --git a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js similarity index 93% rename from waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js rename to waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js index 2c94cb01fd..95ab379515 100644 --- a/waspc/e2e-test/test-outputs/waspBuild-golden/waspBuild/.wasp/out/sdk/wasp/dist/client/operations/core.js +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js @@ -1,17 +1,15 @@ import { useMutation, useQueryClient, useQuery as rqUseQuery, } from "@tanstack/react-query"; +import { makeQueryCacheKey } from "./queries/core"; export { configureQueryClient } from "./queryClient"; // PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); +export function useQuery(query, queryFnArgs, options) { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.'); } - if (!queryFn.queryCacheKey) { - throw new TypeError("queryFn needs to have queryCacheKey property defined."); + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.'); } - const queryKey = queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; - return rqUseQuery(Object.assign({ queryKey, queryFn: () => queryFn(queryKey, queryFnArgs) }, options)); + return rqUseQuery(Object.assign({ queryKey: makeQueryCacheKey(query, queryFnArgs), queryFn: () => query(queryFnArgs) }, options)); } // PUBLIC API /** @@ -168,4 +166,4 @@ function getRqQueryKeyFromSpecifier(querySpecifier) { const [queryFn, ...otherKeys] = querySpecifier; return [...queryFn.queryCacheKey, ...otherKeys]; } -//# sourceMappingURL=core.js.map \ No newline at end of file +//# sourceMappingURL=hooks.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map new file mode 100644 index 0000000000..9048c71ee2 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../client/operations/hooks.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts index 301165fa8e..76ad094f0d 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts @@ -1,4 +1,4 @@ export * from './actions'; export * from './queries'; -export { useAction, useQuery, type OptimisticUpdateDefinition, } from './core'; +export { useAction, useQuery, type OptimisticUpdateDefinition, } from './hooks'; export { configureQueryClient, initializeQueryClient, queryClientInitialized } from './queryClient'; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js index f83307c7b1..fd2c6b29b0 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js @@ -6,7 +6,7 @@ export { // PUBLIC API useAction, // PUBLIC API -useQuery, } from './core'; +useQuery, } from './hooks'; export { // PUBLIC API configureQueryClient, diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js.map index 982c957a9a..a6cf9161ab 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,QAAQ,CAAA;AAEf,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,SAAS,CAAA;AAEhB,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts index 93bbd1ddaa..c70de80ba6 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts @@ -1,12 +1,25 @@ import { Route } from 'wasp/client'; -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Query } from '../core.js'; -export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; -export declare function addMetadataToQuery(query: (...args: any[]) => Promise, metadata: { - relativeQueryPath: string; +import type { GenericBackendOperation, GenericOperationRpc, OperationRpcFor, Query, QueryMetadata } from '../rpc.js'; +export declare function makeQueryCacheKey(query: Query, payload: Input): (string | Input)[]; +export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; +export declare function buildAndRegisterQuery(queryFn: QF, { queryCacheKey, queryRoute, entitiesUsed }: { + queryCacheKey: string[]; queryRoute: Route; entitiesUsed: string[]; -}): void; -export type QueryFor = Query[0], _Awaited<_ReturnType>>; -type GenericBackendQuery = (args: never, context: any) => unknown; +}): QueryForFunction; +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = QueryForFunction>; +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = OperationRpcFor; +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata; export {}; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js index c03f172443..fefdfc58fc 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js @@ -1,18 +1,28 @@ import { callOperation, makeOperationRoute } from '../internal/index.js'; import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources'; +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey(query, payload) { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey; +} +// PRIVATE API (unsed in SDK) export function createQuery(relativeQueryPath, entitiesUsed) { const queryRoute = makeOperationRoute(relativeQueryPath); - async function query(queryKey, queryArgs) { + const queryCacheKey = [relativeQueryPath]; + const queryFn = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs); - return getActiveOptimisticUpdates(queryKey).reduce((result, update) => update(result), serverResult); - } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }); - return query; + const queryCacheKey = makeQueryCacheKey(queryFn, queryArgs); + return getActiveOptimisticUpdates(queryCacheKey).reduce((result, update) => update(result), serverResult); + }; + return buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }); } -// PRIVATE API -export function addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) { - query.queryCacheKey = [relativeQueryPath]; +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }) { + const query = queryFn; + query.queryCacheKey = queryCacheKey; query.route = queryRoute; addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed); + return query; } //# sourceMappingURL=core.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map index dcc40d2693..0ef0547c44 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IAExD,KAAK,UAAU,KAAK,CAAC,QAAQ,EAAE,SAAS;QACtC,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,OAAO,0BAA0B,CAAC,QAAQ,CAAC,CAAC,MAAM,CAChD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAA;IAE1E,OAAO,KAAK,CAAA;AACd,CAAC;AAYD,cAAc;AACd,MAAM,UAAU,kBAAkB,CAChC,KAAK,EACL,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE;IAE/C,KAAK,CAAC,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IACzC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;AAC5D,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,gCAAgC;AAChC,MAAM,UAAU,iBAAiB,CAC/B,KAA2B,EAC3B,OAAc;IAEd,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC;QAC5B,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,aAAa,CAAA;AAC3B,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IACxD,MAAM,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAEzC,MAAM,OAAO,GAAmC,KAAK,EAAE,SAAS,EAAE,EAAE;QAClE,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,MAAM,aAAa,GAAG,iBAAiB,CAAC,OAAiC,EAAE,SAAS,CAAC,CAAA;QACrF,OAAO,0BAA0B,CAAC,aAAa,CAAC,CAAC,MAAM,CACrD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC,CAAA;IAED,OAAO,qBAAqB,CAC1B,OAAO,EACP,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,CAC5C,CAAA;AACH,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,qBAAqB,CACnC,OAAW,EACX,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAC6B;IAEtE,MAAM,KAAK,GAAG,OAA+B,CAAA;IAE7C,KAAK,CAAC,aAAa,GAAG,aAAa,CAAA;IACnC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IAE1D,OAAO,KAAK,CAAA;AACd,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts index a66c6c9feb..9584df69e2 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts @@ -1,4 +1,4 @@ import { type QueryFor } from './core'; import { MySpecialQuery } from 'wasp/server/operations/queries'; export declare const mySpecialQuery: QueryFor; -export { addMetadataToQuery } from './core'; +export { buildAndRegisterQuery } from './core'; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js index d0238ee4f5..4ec9ff9ab0 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js @@ -1,6 +1,6 @@ import { createQuery } from './core'; // PUBLIC API export const mySpecialQuery = createQuery('operations/my-special-query', ['User']); -// PRIVATE API -export { addMetadataToQuery } from './core'; +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map index 57f48b3df9..3d0a9da757 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,WAAW,EAAE,MAAM,QAAQ,CAAA;AAGnD,aAAa;AACb,MAAM,CAAC,MAAM,cAAc,GAA6B,WAAW,CACjE,6BAA6B,EAC7B,CAAC,MAAM,CAAC,CACT,CAAA;AAED,cAAc;AACd,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,WAAW,EAAE,MAAM,QAAQ,CAAA;AAGnD,aAAa;AACb,MAAM,CAAC,MAAM,cAAc,GAA6B,WAAW,CACjE,6BAA6B,EAC7B,CAAC,MAAM,CAAC,CACT,CAAA;AAED,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts new file mode 100644 index 0000000000..ee52ec65b4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts @@ -0,0 +1,38 @@ +import { type Route } from "wasp/client"; +import type { _Awaited, _ReturnType } from "wasp/universal/types"; +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata; +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation; +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation; +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[]; + route: Route; +}; +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = Parameters extends [] ? ClientOperation>> : ClientOperation[0], _Awaited<_ReturnType>>; +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown; +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise; +type ClientOperation = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export {}; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js new file mode 100644 index 0000000000..f3a500abe4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=rpc.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map new file mode 100644 index 0000000000..a51bf309e5 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../client/operations/rpc.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts index 645112861a..89fd0d7587 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts @@ -1,7 +1,7 @@ import { ReactElement } from 'react'; import { type SetupServer } from 'msw/node'; import { RenderResult } from '@testing-library/react'; -import { Query } from 'wasp/client/operations/core'; +import { Query } from 'wasp/client/operations/rpc'; import { Route } from 'wasp/client'; export type MockQuery = (query: Query, resJson: MockOutput) => void; export type MockApi = (route: Route, resJson: unknown) => void; diff --git a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/package.json index 351de46d9a..e51e71e7a1 100644 --- a/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspComplexTest-golden/waspComplexTest/.wasp/out/sdk/wasp/package.json @@ -47,7 +47,7 @@ "./client/auth": "./dist/client/auth/index.js", "./client/crud": "./dist/client/crud/index.js", "./client/operations": "./dist/client/operations/index.js", - "./client/operations/core": "./dist/client/operations/core.js", + "./client/operations/rpc": "./dist/client/operations/rpc.js", "./client/router": "./dist/client/router/index.js", "./client/test": "./dist/client/test/index.js", "./client/test/*": "./dist/client/test/*.js", diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/files.manifest b/waspc/e2e-test/test-outputs/waspJob-golden/files.manifest index eecc360a83..d477a56d42 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/files.manifest +++ b/waspc/e2e-test/test-outputs/waspJob-golden/files.manifest @@ -10,7 +10,7 @@ waspJob/.wasp/out/sdk/wasp/client/config.ts waspJob/.wasp/out/sdk/wasp/client/index.ts waspJob/.wasp/out/sdk/wasp/client/operations/actions/core.ts waspJob/.wasp/out/sdk/wasp/client/operations/actions/index.ts -waspJob/.wasp/out/sdk/wasp/client/operations/core.ts +waspJob/.wasp/out/sdk/wasp/client/operations/hooks.ts waspJob/.wasp/out/sdk/wasp/client/operations/index.ts waspJob/.wasp/out/sdk/wasp/client/operations/internal/index.ts waspJob/.wasp/out/sdk/wasp/client/operations/internal/resources.js @@ -18,6 +18,7 @@ waspJob/.wasp/out/sdk/wasp/client/operations/internal/updateHandlersMap.js waspJob/.wasp/out/sdk/wasp/client/operations/queries/core.ts waspJob/.wasp/out/sdk/wasp/client/operations/queries/index.ts waspJob/.wasp/out/sdk/wasp/client/operations/queryClient.ts +waspJob/.wasp/out/sdk/wasp/client/operations/rpc.ts waspJob/.wasp/out/sdk/wasp/client/router/Link.tsx waspJob/.wasp/out/sdk/wasp/client/router/index.ts waspJob/.wasp/out/sdk/wasp/client/router/linkHelpers.ts @@ -44,9 +45,9 @@ waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/index.d.ts waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js.map -waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts -waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js -waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts +waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js +waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -68,6 +69,9 @@ waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map waspJob/.wasp/out/sdk/wasp/dist/client/operations/queryClient.d.ts waspJob/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js waspJob/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts +waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js +waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map waspJob/.wasp/out/sdk/wasp/dist/client/router/Link.d.ts waspJob/.wasp/out/sdk/wasp/dist/client/router/Link.jsx waspJob/.wasp/out/sdk/wasp/dist/client/router/Link.jsx.map diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums index b81a035a21..3e18d566cc 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/.waspchecksums @@ -32,7 +32,7 @@ "file", "../out/sdk/wasp/client/operations/actions/core.ts" ], - "016623c0ebdc1b88d746fa1345015b3cb9653429abdc13a9147a952bff83a927" + "d19dba04947e4015af69d90dd160ec5f4ed020bfa905bc37bcd5d980517097ae" ], [ [ @@ -44,16 +44,16 @@ [ [ "file", - "../out/sdk/wasp/client/operations/core.ts" + "../out/sdk/wasp/client/operations/hooks.ts" ], - "bad860771b16a0d4830fab22de8b85e63c840d47dc3728728a23b8ada91061ef" + "eb4362162aad4b605781e2e33facef83935a7df4101cc0a77097ceaff3a0b360" ], [ [ "file", "../out/sdk/wasp/client/operations/index.ts" ], - "4a66c90319dd7ef0d3a8e6c1f571037c7dfd9778b9def6e951813dbc4b4dcef3" + "edcdc3798590e62b778115b3818df8cc69fa5a8bb3a7fe9fa6d6d5ea706d14c4" ], [ [ @@ -81,14 +81,14 @@ "file", "../out/sdk/wasp/client/operations/queries/core.ts" ], - "5f30328d93582f9c8444720e99f45c19c8647f052b7fbcf5f71b578b9241ac96" + "cce982751b463494c048efd683dddb8d4e617d2f354722a79961199990c7201a" ], [ [ "file", "../out/sdk/wasp/client/operations/queries/index.ts" ], - "882410504b909cc421d50a27c39952f664ba3457438ce746a95d9cab3431944c" + "c92c64425986a38f835211c2693380a8b13904cb78bbf6f6ae880e56ade51686" ], [ [ @@ -97,6 +97,13 @@ ], "5c1d87ac10513788bcde7ebc7c10601b9ad0854cddff355e8fb7e2d4685ecdef" ], + [ + [ + "file", + "../out/sdk/wasp/client/operations/rpc.ts" + ], + "5ab471422e7916c33a0931ce8d499d7d40191802ce2c6f3343b45c623a963566" + ], [ [ "file", @@ -137,7 +144,7 @@ "file", "../out/sdk/wasp/client/test/vitest/helpers.tsx" ], - "b2362e8f80134137fda2f8bb43ef7c0d7ae8aadf8a7adfa472d42d6699e9d918" + "b44ff591a2eebfff4de9fa9e9e1b89f1f22f523f03ab0febc19ff3999721b39a" ], [ [ @@ -200,7 +207,7 @@ "file", "../out/sdk/wasp/package.json" ], - "3b782f30f90af25108f881b4e7d28cd6a8c2894d169dd78c076cf47d76598440" + "a675b7fce46675fe7fc2f5a4edabe8abca4db9cd90a03340d9cf9c54c0e7539f" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/actions/core.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/actions/core.ts index f5db25aff2..c24f726ef3 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/actions/core.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/actions/core.ts @@ -1,5 +1,5 @@ -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Action } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { registerActionInProgress, @@ -7,7 +7,7 @@ import { } from '../internal/resources.js' // PRIVATE API -export function createAction( +export function createAction( relativeActionRoute: string, entitiesUsed: unknown[] ): ActionFor { @@ -41,8 +41,5 @@ export function createAction( } // PRIVATE API -export type ActionFor = - Action[0], _Awaited<_ReturnType>> - - -type GenericBackendAction = (args: never, context: any) => unknown +export type ActionFor = + OperationRpcFor diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/core.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/core.ts deleted file mode 100644 index 282c4698a7..0000000000 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/core.ts +++ /dev/null @@ -1,346 +0,0 @@ -import { - QueryClient, - QueryKey, - useMutation, - UseMutationOptions, - useQueryClient, - useQuery as rqUseQuery, - UseQueryResult, -} from "@tanstack/react-query"; -export { configureQueryClient } from "./queryClient"; - -// PRIVATE API (but should maybe be public, users use values of this type) -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; - -// PUBLIC API -export function useQuery( - queryFn: Query, - queryFnArgs?: Input, - options?: any -): UseQueryResult; - -// PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); - } - if (!queryFn.queryCacheKey) { - throw new TypeError( - "queryFn needs to have queryCacheKey property defined." - ); - } - - const queryKey = - queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; - return rqUseQuery({ - queryKey, - queryFn: () => queryFn(queryKey, queryFnArgs), - ...options, - }); -} - -// PRIVATE API (but should maybe be public, users use values of this type) -export type Action = [Input] extends [never] - ? (args?: unknown) => Promise - : (args: Input) => Promise; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. - * - */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; - -// PUBLIC API -/** - * A documented (public) way to define optimistic updates. - */ -export type OptimisticUpdateDefinition = { - getQuerySpecifier: GetQuerySpecifier; - updateQuery: UpdateQuery; -}; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and returns a Wasp Query specifier. - */ -export type GetQuerySpecifier = ( - item: ActionInput -) => QuerySpecifier; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and the previous state of the cache, and returns - * the desired (new) state of the cache. - */ -export type UpdateQuery = ( - item: ActionInput, - oldData: CachedData | undefined -) => CachedData; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A public query specifier used for addressing Wasp queries. See our docs for details: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - */ -export type QuerySpecifier = [Query, ...any[]]; - -// PUBLIC API -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export function useAction( - actionFn: Action, - actionOptions?: ActionOptions -): typeof actionFn { - const queryClient = useQueryClient(); - - let mutationFn = actionFn; - let options = {}; - if (actionOptions?.optimisticUpdates) { - const optimisticUpdatesDefinitions = actionOptions.optimisticUpdates.map( - translateToInternalDefinition - ); - mutationFn = makeOptimisticUpdateMutationFn( - actionFn, - optimisticUpdatesDefinitions - ); - options = makeRqOptimisticUpdateOptions( - queryClient, - optimisticUpdatesDefinitions - ); - } - - // NOTE: We decided to hide React Query's extra mutation features (e.g., - // isLoading, onSuccess and onError callbacks, synchronous mutate) and only - // expose a simple async function whose API matches the original Action. - // We did this to avoid cluttering the API with stuff we're not sure we need - // yet (e.g., isLoading), to postpone the action vs mutation dilemma, and to - // clearly separate our opinionated API from React Query's lower-level - // advanced API (which users can also use) - const mutation = useMutation(mutationFn, options); - return (args) => mutation.mutateAsync(args); -} - -/** - * An internal (undocumented, private, desugared) way of defining optimistic updates. - */ -type InternalOptimisticUpdateDefinition = { - getQueryKey: (item: ActionInput) => QueryKey; - updateQuery: UpdateQuery; -}; - -/** - * An UpdateQuery function "instantiated" with a specific item. It only takes - * the current state of the cache and returns the desired (new) state of the - * cache. - */ -type SpecificUpdateQuery = (oldData: CachedData) => CachedData; - -/** - * A specific, "instantiated" optimistic update definition which contains a - * fully-constructed query key and a specific update function. - */ -type SpecificOptimisticUpdateDefinition = { - queryKey: QueryKey; - updateQuery: SpecificUpdateQuery; -}; - -type InternalAction = Action & { - internal( - item: Input, - optimisticUpdateDefinitions: SpecificOptimisticUpdateDefinition[] - ): Promise; -}; - -/** - * Translates/Desugars a public optimistic update definition object into a - * definition object our system uses internally. - * - * @param publicOptimisticUpdateDefinition An optimistic update definition - * object that's a part of the public API: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - * @returns An internally-used optimistic update definition object. - */ -function translateToInternalDefinition( - publicOptimisticUpdateDefinition: OptimisticUpdateDefinition -): InternalOptimisticUpdateDefinition { - const { getQuerySpecifier, updateQuery } = publicOptimisticUpdateDefinition; - - const definitionErrors = []; - if (typeof getQuerySpecifier !== "function") { - definitionErrors.push("`getQuerySpecifier` is not a function."); - } - if (typeof updateQuery !== "function") { - definitionErrors.push("`updateQuery` is not a function."); - } - if (definitionErrors.length) { - throw new TypeError( - `Invalid optimistic update definition: ${definitionErrors.join(", ")}.` - ); - } - - return { - getQueryKey: (item) => getRqQueryKeyFromSpecifier(getQuerySpecifier(item)), - updateQuery, - }; -} - -/** - * Creates a function that performs an action while telling it about the - * optimistic updates it caused. - * - * @param actionFn The Wasp Action. - * @param optimisticUpdateDefinitions The optimisitc updates the action causes. - * @returns An decorated action which performs optimistic updates. - */ -function makeOptimisticUpdateMutationFn( - actionFn: Action, - optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition< - Input, - CachedData - >[] -): typeof actionFn { - return function performActionWithOptimisticUpdates(item) { - const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map( - (generalDefinition) => - getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item) - ); - return (actionFn as InternalAction).internal( - item, - specificOptimisticUpdateDefinitions - ); - }; -} - -/** - * Given a ReactQuery query client and our internal definition of optimistic - * updates, this function constructs an object describing those same optimistic - * updates in a format we can pass into React Query's useMutation hook. In other - * words, it translates our optimistic updates definition into React Query's - * optimistic updates definition. Check their docs for details: - * https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates - * - * @param queryClient The QueryClient instance used by React Query. - * @param optimisticUpdateDefinitions A list containing internal optimistic - * updates definition objects (i.e., a list where each object carries the - * instructions for performing particular optimistic update). - * @returns An object containing 'onMutate' and 'onError' functions - * corresponding to the given optimistic update definitions (check the docs - * linked above for details). - */ -function makeRqOptimisticUpdateOptions( - queryClient: QueryClient, - optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition< - ActionInput, - CachedData - >[] -): Pick { - async function onMutate(item) { - const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map( - (generalDefinition) => - getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item) - ); - - // Cancel any outgoing refetches (so they don't overwrite our optimistic update). - // Theoretically, we can be a bit faster. Instead of awaiting the - // cancellation of all queries, we could cancel and update them in parallel. - // However, awaiting cancellation hasn't yet proven to be a performance bottleneck. - await Promise.all( - specificOptimisticUpdateDefinitions.map(({ queryKey }) => - queryClient.cancelQueries(queryKey) - ) - ); - - // We're using a Map to correctly serialize query keys that contain objects. - const previousData = new Map(); - specificOptimisticUpdateDefinitions.forEach(({ queryKey, updateQuery }) => { - // Snapshot the currently cached value. - const previousDataForQuery: CachedData = - queryClient.getQueryData(queryKey); - - // Attempt to optimistically update the cache using the new value. - try { - queryClient.setQueryData(queryKey, updateQuery); - } catch (e) { - console.error( - "The `updateQuery` function threw an exception, skipping optimistic update:" - ); - console.error(e); - } - - // Remember the snapshotted value to restore in case of an error. - previousData.set(queryKey, previousDataForQuery); - }); - - return { previousData }; - } - - function onError(_err, _item, context) { - // All we do in case of an error is roll back all optimistic updates. We ensure - // not to do anything else because React Query rethrows the error. This allows - // the programmer to handle the error as they usually would (i.e., we want the - // error handling to work as it would if the programmer wasn't using optimistic - // updates). - context.previousData.forEach(async (data, queryKey) => { - await queryClient.cancelQueries(queryKey); - queryClient.setQueryData(queryKey, data); - }); - } - - return { - onMutate, - onError, - }; -} - -/** - * Constructs the definition for optimistically updating a specific item. It - * uses a closure over the updated item to construct an item-specific query key - * (e.g., useful when the query key depends on an ID). - * - * @param optimisticUpdateDefinition The general, "uninstantiated" optimistic - * update definition with a function for constructing the query key. - * @param item The item triggering the Action/optimistic update (i.e., the - * argument passed to the Action). - * @returns A specific optimistic update definition which corresponds to the - * provided definition and closes over the provided item. - */ -function getOptimisticUpdateDefinitionForSpecificItem( - optimisticUpdateDefinition: InternalOptimisticUpdateDefinition< - ActionInput, - CachedData - >, - item: ActionInput -): SpecificOptimisticUpdateDefinition { - const { getQueryKey, updateQuery } = optimisticUpdateDefinition; - return { - queryKey: getQueryKey(item), - updateQuery: (old) => updateQuery(item, old), - }; -} - -/** - * Translates a Wasp query specifier to a query cache key used by React Query. - * - * @param querySpecifier A query specifier that's a part of the public API: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - * @returns A cache key React Query internally uses for addressing queries. - */ -function getRqQueryKeyFromSpecifier( - querySpecifier: QuerySpecifier -): QueryKey { - const [queryFn, ...otherKeys] = querySpecifier; - return [...(queryFn as any).queryCacheKey, ...otherKeys]; -} diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/hooks.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/hooks.ts new file mode 100644 index 0000000000..fa913a44c1 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/hooks.ts @@ -0,0 +1,328 @@ +import { + QueryClient, + QueryKey, + useMutation, + UseMutationOptions, + useQueryClient, + useQuery as rqUseQuery, + UseQueryResult, +} from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; +import { makeQueryCacheKey } from "./queries/core"; +export { configureQueryClient } from "./queryClient"; + +// PUBLIC API +export function useQuery( + query: Query, + queryFnArgs?: Input, + options?: any +): UseQueryResult { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.') + } + + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.') + } + + return rqUseQuery({ + queryKey: makeQueryCacheKey(query, queryFnArgs), + queryFn: () => query(queryFnArgs), + ...options, + }) +} + +// PUBLIC API +/** + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). + * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. + */ +export function useAction( + actionFn: Action, + actionOptions?: ActionOptions +): typeof actionFn { + const queryClient = useQueryClient(); + + let mutationFn = actionFn; + let options = {}; + if (actionOptions?.optimisticUpdates) { + const optimisticUpdatesDefinitions = actionOptions.optimisticUpdates.map( + translateToInternalDefinition + ); + mutationFn = makeOptimisticUpdateMutationFn( + actionFn, + optimisticUpdatesDefinitions + ); + options = makeRqOptimisticUpdateOptions( + queryClient, + optimisticUpdatesDefinitions + ); + } + + // NOTE: We decided to hide React Query's extra mutation features (e.g., + // isLoading, onSuccess and onError callbacks, synchronous mutate) and only + // expose a simple async function whose API matches the original Action. + // We did this to avoid cluttering the API with stuff we're not sure we need + // yet (e.g., isLoading), to postpone the action vs mutation dilemma, and to + // clearly separate our opinionated API from React Query's lower-level + // advanced API (which users can also use) + const mutation = useMutation(mutationFn, options); + return (args) => mutation.mutateAsync(args); +} + +// PUBLIC API +/** + * A documented (public) way to define optimistic updates. + */ +export type OptimisticUpdateDefinition = { + getQuerySpecifier: GetQuerySpecifier; + updateQuery: UpdateQuery; +}; + +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; + +/** + * A function that takes an item and returns a Wasp Query specifier. + */ +type GetQuerySpecifier = ( + item: ActionInput +) => QuerySpecifier; + +/** + * A function that takes an item and the previous state of the cache, and returns + * the desired (new) state of the cache. + */ +type UpdateQuery = ( + item: ActionInput, + oldData: CachedData | undefined +) => CachedData; + +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * A public query specifier used for addressing Wasp queries. See our docs for details: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + */ +type QuerySpecifier = [Query, ...any[]]; + + +/** + * An internal (undocumented, private, desugared) way of defining optimistic updates. + */ +type InternalOptimisticUpdateDefinition = { + getQueryKey: (item: ActionInput) => QueryKey; + updateQuery: UpdateQuery; +}; + +/** + * An UpdateQuery function "instantiated" with a specific item. It only takes + * the current state of the cache and returns the desired (new) state of the + * cache. + */ +type SpecificUpdateQuery = (oldData: CachedData) => CachedData; + +/** + * A specific, "instantiated" optimistic update definition which contains a + * fully-constructed query key and a specific update function. + */ +type SpecificOptimisticUpdateDefinition = { + queryKey: QueryKey; + updateQuery: SpecificUpdateQuery; +}; + +type InternalAction = Action & { + internal( + item: Input, + optimisticUpdateDefinitions: SpecificOptimisticUpdateDefinition[] + ): Promise; +}; + +/** + * Translates/Desugars a public optimistic update definition object into a + * definition object our system uses internally. + * + * @param publicOptimisticUpdateDefinition An optimistic update definition + * object that's a part of the public API: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + * @returns An internally-used optimistic update definition object. + */ +function translateToInternalDefinition( + publicOptimisticUpdateDefinition: OptimisticUpdateDefinition +): InternalOptimisticUpdateDefinition { + const { getQuerySpecifier, updateQuery } = publicOptimisticUpdateDefinition; + + const definitionErrors = []; + if (typeof getQuerySpecifier !== "function") { + definitionErrors.push("`getQuerySpecifier` is not a function."); + } + if (typeof updateQuery !== "function") { + definitionErrors.push("`updateQuery` is not a function."); + } + if (definitionErrors.length) { + throw new TypeError( + `Invalid optimistic update definition: ${definitionErrors.join(", ")}.` + ); + } + + return { + getQueryKey: (item) => getRqQueryKeyFromSpecifier(getQuerySpecifier(item)), + updateQuery, + }; +} + +/** + * Creates a function that performs an action while telling it about the + * optimistic updates it caused. + * + * @param actionFn The Wasp Action. + * @param optimisticUpdateDefinitions The optimisitc updates the action causes. + * @returns An decorated action which performs optimistic updates. + */ +function makeOptimisticUpdateMutationFn( + actionFn: Action, + optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition< + Input, + CachedData + >[] +): typeof actionFn { + return function performActionWithOptimisticUpdates(item) { + const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map( + (generalDefinition) => + getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item) + ); + return (actionFn as InternalAction).internal( + item, + specificOptimisticUpdateDefinitions + ); + }; +} + +/** + * Given a ReactQuery query client and our internal definition of optimistic + * updates, this function constructs an object describing those same optimistic + * updates in a format we can pass into React Query's useMutation hook. In other + * words, it translates our optimistic updates definition into React Query's + * optimistic updates definition. Check their docs for details: + * https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates + * + * @param queryClient The QueryClient instance used by React Query. + * @param optimisticUpdateDefinitions A list containing internal optimistic + * updates definition objects (i.e., a list where each object carries the + * instructions for performing particular optimistic update). + * @returns An object containing 'onMutate' and 'onError' functions + * corresponding to the given optimistic update definitions (check the docs + * linked above for details). + */ +function makeRqOptimisticUpdateOptions( + queryClient: QueryClient, + optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition< + ActionInput, + CachedData + >[] +): Pick { + async function onMutate(item) { + const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map( + (generalDefinition) => + getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item) + ); + + // Cancel any outgoing refetches (so they don't overwrite our optimistic update). + // Theoretically, we can be a bit faster. Instead of awaiting the + // cancellation of all queries, we could cancel and update them in parallel. + // However, awaiting cancellation hasn't yet proven to be a performance bottleneck. + await Promise.all( + specificOptimisticUpdateDefinitions.map(({ queryKey }) => + queryClient.cancelQueries(queryKey) + ) + ); + + // We're using a Map to correctly serialize query keys that contain objects. + const previousData = new Map(); + specificOptimisticUpdateDefinitions.forEach(({ queryKey, updateQuery }) => { + // Snapshot the currently cached value. + const previousDataForQuery: CachedData = + queryClient.getQueryData(queryKey); + + // Attempt to optimistically update the cache using the new value. + try { + queryClient.setQueryData(queryKey, updateQuery); + } catch (e) { + console.error( + "The `updateQuery` function threw an exception, skipping optimistic update:" + ); + console.error(e); + } + + // Remember the snapshotted value to restore in case of an error. + previousData.set(queryKey, previousDataForQuery); + }); + + return { previousData }; + } + + function onError(_err, _item, context) { + // All we do in case of an error is roll back all optimistic updates. We ensure + // not to do anything else because React Query rethrows the error. This allows + // the programmer to handle the error as they usually would (i.e., we want the + // error handling to work as it would if the programmer wasn't using optimistic + // updates). + context.previousData.forEach(async (data, queryKey) => { + await queryClient.cancelQueries(queryKey); + queryClient.setQueryData(queryKey, data); + }); + } + + return { + onMutate, + onError, + }; +} + +/** + * Constructs the definition for optimistically updating a specific item. It + * uses a closure over the updated item to construct an item-specific query key + * (e.g., useful when the query key depends on an ID). + * + * @param optimisticUpdateDefinition The general, "uninstantiated" optimistic + * update definition with a function for constructing the query key. + * @param item The item triggering the Action/optimistic update (i.e., the + * argument passed to the Action). + * @returns A specific optimistic update definition which corresponds to the + * provided definition and closes over the provided item. + */ +function getOptimisticUpdateDefinitionForSpecificItem( + optimisticUpdateDefinition: InternalOptimisticUpdateDefinition< + ActionInput, + CachedData + >, + item: ActionInput +): SpecificOptimisticUpdateDefinition { + const { getQueryKey, updateQuery } = optimisticUpdateDefinition; + return { + queryKey: getQueryKey(item), + updateQuery: (old) => updateQuery(item, old), + }; +} + +/** + * Translates a Wasp query specifier to a query cache key used by React Query. + * + * @param querySpecifier A query specifier that's a part of the public API: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + * @returns A cache key React Query internally uses for addressing queries. + */ +function getRqQueryKeyFromSpecifier( + querySpecifier: QuerySpecifier +): QueryKey { + const [queryFn, ...otherKeys] = querySpecifier; + return [...(queryFn as any).queryCacheKey, ...otherKeys]; +} diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/index.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/index.ts index ec9ca9f689..4dc2691035 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/index.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/index.ts @@ -10,7 +10,7 @@ export { useQuery, // PUBLIC API type OptimisticUpdateDefinition, -} from './core' +} from './hooks' export { // PUBLIC API diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/queries/core.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/queries/core.ts index bdc0a9db75..36cd6ad067 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/queries/core.ts @@ -1,53 +1,83 @@ import { Route } from 'wasp/client' -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Query } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { + GenericBackendOperation, + GenericOperationRpc, + OperationRpcFor, + Query, + QueryMetadata, +} from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources' -export function createQuery( +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey( + query: Query, + payload: Input +): (string | Input)[] { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey +} + +// PRIVATE API (unsed in SDK) +export function createQuery( relativeQueryPath: string, entitiesUsed: string[] ): QueryFor { const queryRoute = makeOperationRoute(relativeQueryPath) + const queryCacheKey = [relativeQueryPath] - async function query(queryKey, queryArgs) { + const queryFn: QueryFunctionFor = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) - return getActiveOptimisticUpdates(queryKey).reduce( + const queryCacheKey = makeQueryCacheKey(queryFn as QueryFor, queryArgs) + return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), serverResult, ) } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) - - return query + return buildAndRegisterQuery( + queryFn, + { queryCacheKey, queryRoute, entitiesUsed }, + ) } -// PRIVATE API -export function addMetadataToQuery( - query: (...args: any[]) => Promise, - metadata: { - relativeQueryPath: string - queryRoute: Route - entitiesUsed: string[] - } -): void - -// PRIVATE API -export function addMetadataToQuery( - query, - { relativeQueryPath, queryRoute, entitiesUsed } -) { - query.queryCacheKey = [relativeQueryPath] +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery( + queryFn: QF, + { queryCacheKey, queryRoute, entitiesUsed }: + { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } +): QueryForFunction { + const query = queryFn as QueryForFunction + + query.queryCacheKey = queryCacheKey query.route = queryRoute addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) + + return query } -export type QueryFor = - Query[0], _Awaited<_ReturnType>> +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = + QueryForFunction> +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = + OperationRpcFor -type GenericBackendQuery = (args: never, context: any) => unknown \ No newline at end of file +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/queries/index.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/queries/index.ts index eeb2cf5a11..af63c67c63 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/queries/index.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/queries/index.ts @@ -1,4 +1,4 @@ import { type QueryFor, createQuery } from './core' -// PRIVATE API -export { addMetadataToQuery } from './core' +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core' diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/rpc.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/rpc.ts new file mode 100644 index 0000000000..45a8dbbf47 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/operations/rpc.ts @@ -0,0 +1,77 @@ +import { type Route } from "wasp/client"; +import type { + _Awaited, + _ReturnType, +} from "wasp/universal/types" + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type). +// +// Frontend queries are functions with some extra properties (metadata). +// +// To simplify working with the type (i.e., referencing the type's two different +// components), we've defined it as an intersection of two distinct types: +// one representing the function (QueryFunction), and the other representing the +// metadata (QueryMetadata) . +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type) +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation + +// PRIVATE API (for SDK) +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation + +// PRIVATE API (for SDK) +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[] + route: Route +} + +// PRIVATE API (needed in SDK) +// Explanation: +// - Custom `_Awaited` and `_ReturnType` - Read the comments above their +// definitions. +// - `Parameters extends []` - See here: +// https://github.com/wasp-lang/wasp/pull/1992/files#r1583040080 +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = + Parameters extends [] + ? ClientOperation>> + : ClientOperation< + Parameters[0], + _Awaited<_ReturnType> + > + +// PRIVATE API (needed in SDK) +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown + +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise + +// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 +type ClientOperation = [Input] extends [never] + ? (args?: unknown) => Promise + : (args: Input) => Promise; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx index 8e6085f34c..96ff5e90e8 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx @@ -6,7 +6,7 @@ import { BrowserRouter as Router } from 'react-router-dom' import { render, RenderResult, cleanup } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { beforeAll, afterEach, afterAll } from 'vitest' -import { Query } from 'wasp/client/operations/core' +import { Query } from 'wasp/client/operations/rpc' import { config } from 'wasp/client' import { HttpMethod, Route } from 'wasp/client' diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts index e1708451f8..4b8c455fd4 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts @@ -1,6 +1,3 @@ -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Action } from '../core.js'; -export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; -export type ActionFor = Action[0], _Awaited<_ReturnType>>; -type GenericBackendAction = (args: never, context: any) => unknown; -export {}; +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js'; +export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; +export type ActionFor = OperationRpcFor; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts deleted file mode 100644 index a23b24ebd6..0000000000 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { UseQueryResult } from "@tanstack/react-query"; -export { configureQueryClient } from "./queryClient"; -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; -export declare function useQuery(queryFn: Query, queryFnArgs?: Input, options?: any): UseQueryResult; -export type Action = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; -/** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. - * - */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; -/** - * A documented (public) way to define optimistic updates. - */ -export type OptimisticUpdateDefinition = { - getQuerySpecifier: GetQuerySpecifier; - updateQuery: UpdateQuery; -}; -/** - * A function that takes an item and returns a Wasp Query specifier. - */ -export type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; -/** - * A function that takes an item and the previous state of the cache, and returns - * the desired (new) state of the cache. - */ -export type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; -/** - * A public query specifier used for addressing Wasp queries. See our docs for details: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - */ -export type QuerySpecifier = [Query, ...any[]]; -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js deleted file mode 100644 index 2c94cb01fd..0000000000 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js +++ /dev/null @@ -1,171 +0,0 @@ -import { useMutation, useQueryClient, useQuery as rqUseQuery, } from "@tanstack/react-query"; -export { configureQueryClient } from "./queryClient"; -// PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); - } - if (!queryFn.queryCacheKey) { - throw new TypeError("queryFn needs to have queryCacheKey property defined."); - } - const queryKey = queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; - return rqUseQuery(Object.assign({ queryKey, queryFn: () => queryFn(queryKey, queryFnArgs) }, options)); -} -// PUBLIC API -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export function useAction(actionFn, actionOptions) { - const queryClient = useQueryClient(); - let mutationFn = actionFn; - let options = {}; - if (actionOptions === null || actionOptions === void 0 ? void 0 : actionOptions.optimisticUpdates) { - const optimisticUpdatesDefinitions = actionOptions.optimisticUpdates.map(translateToInternalDefinition); - mutationFn = makeOptimisticUpdateMutationFn(actionFn, optimisticUpdatesDefinitions); - options = makeRqOptimisticUpdateOptions(queryClient, optimisticUpdatesDefinitions); - } - // NOTE: We decided to hide React Query's extra mutation features (e.g., - // isLoading, onSuccess and onError callbacks, synchronous mutate) and only - // expose a simple async function whose API matches the original Action. - // We did this to avoid cluttering the API with stuff we're not sure we need - // yet (e.g., isLoading), to postpone the action vs mutation dilemma, and to - // clearly separate our opinionated API from React Query's lower-level - // advanced API (which users can also use) - const mutation = useMutation(mutationFn, options); - return (args) => mutation.mutateAsync(args); -} -/** - * Translates/Desugars a public optimistic update definition object into a - * definition object our system uses internally. - * - * @param publicOptimisticUpdateDefinition An optimistic update definition - * object that's a part of the public API: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - * @returns An internally-used optimistic update definition object. - */ -function translateToInternalDefinition(publicOptimisticUpdateDefinition) { - const { getQuerySpecifier, updateQuery } = publicOptimisticUpdateDefinition; - const definitionErrors = []; - if (typeof getQuerySpecifier !== "function") { - definitionErrors.push("`getQuerySpecifier` is not a function."); - } - if (typeof updateQuery !== "function") { - definitionErrors.push("`updateQuery` is not a function."); - } - if (definitionErrors.length) { - throw new TypeError(`Invalid optimistic update definition: ${definitionErrors.join(", ")}.`); - } - return { - getQueryKey: (item) => getRqQueryKeyFromSpecifier(getQuerySpecifier(item)), - updateQuery, - }; -} -/** - * Creates a function that performs an action while telling it about the - * optimistic updates it caused. - * - * @param actionFn The Wasp Action. - * @param optimisticUpdateDefinitions The optimisitc updates the action causes. - * @returns An decorated action which performs optimistic updates. - */ -function makeOptimisticUpdateMutationFn(actionFn, optimisticUpdateDefinitions) { - return function performActionWithOptimisticUpdates(item) { - const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map((generalDefinition) => getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)); - return actionFn.internal(item, specificOptimisticUpdateDefinitions); - }; -} -/** - * Given a ReactQuery query client and our internal definition of optimistic - * updates, this function constructs an object describing those same optimistic - * updates in a format we can pass into React Query's useMutation hook. In other - * words, it translates our optimistic updates definition into React Query's - * optimistic updates definition. Check their docs for details: - * https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates - * - * @param queryClient The QueryClient instance used by React Query. - * @param optimisticUpdateDefinitions A list containing internal optimistic - * updates definition objects (i.e., a list where each object carries the - * instructions for performing particular optimistic update). - * @returns An object containing 'onMutate' and 'onError' functions - * corresponding to the given optimistic update definitions (check the docs - * linked above for details). - */ -function makeRqOptimisticUpdateOptions(queryClient, optimisticUpdateDefinitions) { - async function onMutate(item) { - const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map((generalDefinition) => getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)); - // Cancel any outgoing refetches (so they don't overwrite our optimistic update). - // Theoretically, we can be a bit faster. Instead of awaiting the - // cancellation of all queries, we could cancel and update them in parallel. - // However, awaiting cancellation hasn't yet proven to be a performance bottleneck. - await Promise.all(specificOptimisticUpdateDefinitions.map(({ queryKey }) => queryClient.cancelQueries(queryKey))); - // We're using a Map to correctly serialize query keys that contain objects. - const previousData = new Map(); - specificOptimisticUpdateDefinitions.forEach(({ queryKey, updateQuery }) => { - // Snapshot the currently cached value. - const previousDataForQuery = queryClient.getQueryData(queryKey); - // Attempt to optimistically update the cache using the new value. - try { - queryClient.setQueryData(queryKey, updateQuery); - } - catch (e) { - console.error("The `updateQuery` function threw an exception, skipping optimistic update:"); - console.error(e); - } - // Remember the snapshotted value to restore in case of an error. - previousData.set(queryKey, previousDataForQuery); - }); - return { previousData }; - } - function onError(_err, _item, context) { - // All we do in case of an error is roll back all optimistic updates. We ensure - // not to do anything else because React Query rethrows the error. This allows - // the programmer to handle the error as they usually would (i.e., we want the - // error handling to work as it would if the programmer wasn't using optimistic - // updates). - context.previousData.forEach(async (data, queryKey) => { - await queryClient.cancelQueries(queryKey); - queryClient.setQueryData(queryKey, data); - }); - } - return { - onMutate, - onError, - }; -} -/** - * Constructs the definition for optimistically updating a specific item. It - * uses a closure over the updated item to construct an item-specific query key - * (e.g., useful when the query key depends on an ID). - * - * @param optimisticUpdateDefinition The general, "uninstantiated" optimistic - * update definition with a function for constructing the query key. - * @param item The item triggering the Action/optimistic update (i.e., the - * argument passed to the Action). - * @returns A specific optimistic update definition which corresponds to the - * provided definition and closes over the provided item. - */ -function getOptimisticUpdateDefinitionForSpecificItem(optimisticUpdateDefinition, item) { - const { getQueryKey, updateQuery } = optimisticUpdateDefinition; - return { - queryKey: getQueryKey(item), - updateQuery: (old) => updateQuery(item, old), - }; -} -/** - * Translates a Wasp query specifier to a query cache key used by React Query. - * - * @param querySpecifier A query specifier that's a part of the public API: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - * @returns A cache key React Query internally uses for addressing queries. - */ -function getRqQueryKeyFromSpecifier(querySpecifier) { - const [queryFn, ...otherKeys] = querySpecifier; - return [...queryFn.queryCacheKey, ...otherKeys]; -} -//# sourceMappingURL=core.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js.map deleted file mode 100644 index 20d72dc15e..0000000000 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts new file mode 100644 index 0000000000..36a5e0b65b --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts @@ -0,0 +1,41 @@ +import { UseQueryResult } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; +export { configureQueryClient } from "./queryClient"; +export declare function useQuery(query: Query, queryFnArgs?: Input, options?: any): UseQueryResult; +/** + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). + * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. + */ +export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; +/** + * A documented (public) way to define optimistic updates. + */ +export type OptimisticUpdateDefinition = { + getQuerySpecifier: GetQuerySpecifier; + updateQuery: UpdateQuery; +}; +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; +/** + * A function that takes an item and returns a Wasp Query specifier. + */ +type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; +/** + * A function that takes an item and the previous state of the cache, and returns + * the desired (new) state of the cache. + */ +type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; +/** + * A public query specifier used for addressing Wasp queries. See our docs for details: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + */ +type QuerySpecifier = [Query, ...any[]]; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js new file mode 100644 index 0000000000..95ab379515 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js @@ -0,0 +1,169 @@ +import { useMutation, useQueryClient, useQuery as rqUseQuery, } from "@tanstack/react-query"; +import { makeQueryCacheKey } from "./queries/core"; +export { configureQueryClient } from "./queryClient"; +// PUBLIC API +export function useQuery(query, queryFnArgs, options) { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.'); + } + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.'); + } + return rqUseQuery(Object.assign({ queryKey: makeQueryCacheKey(query, queryFnArgs), queryFn: () => query(queryFnArgs) }, options)); +} +// PUBLIC API +/** + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). + * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. + */ +export function useAction(actionFn, actionOptions) { + const queryClient = useQueryClient(); + let mutationFn = actionFn; + let options = {}; + if (actionOptions === null || actionOptions === void 0 ? void 0 : actionOptions.optimisticUpdates) { + const optimisticUpdatesDefinitions = actionOptions.optimisticUpdates.map(translateToInternalDefinition); + mutationFn = makeOptimisticUpdateMutationFn(actionFn, optimisticUpdatesDefinitions); + options = makeRqOptimisticUpdateOptions(queryClient, optimisticUpdatesDefinitions); + } + // NOTE: We decided to hide React Query's extra mutation features (e.g., + // isLoading, onSuccess and onError callbacks, synchronous mutate) and only + // expose a simple async function whose API matches the original Action. + // We did this to avoid cluttering the API with stuff we're not sure we need + // yet (e.g., isLoading), to postpone the action vs mutation dilemma, and to + // clearly separate our opinionated API from React Query's lower-level + // advanced API (which users can also use) + const mutation = useMutation(mutationFn, options); + return (args) => mutation.mutateAsync(args); +} +/** + * Translates/Desugars a public optimistic update definition object into a + * definition object our system uses internally. + * + * @param publicOptimisticUpdateDefinition An optimistic update definition + * object that's a part of the public API: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + * @returns An internally-used optimistic update definition object. + */ +function translateToInternalDefinition(publicOptimisticUpdateDefinition) { + const { getQuerySpecifier, updateQuery } = publicOptimisticUpdateDefinition; + const definitionErrors = []; + if (typeof getQuerySpecifier !== "function") { + definitionErrors.push("`getQuerySpecifier` is not a function."); + } + if (typeof updateQuery !== "function") { + definitionErrors.push("`updateQuery` is not a function."); + } + if (definitionErrors.length) { + throw new TypeError(`Invalid optimistic update definition: ${definitionErrors.join(", ")}.`); + } + return { + getQueryKey: (item) => getRqQueryKeyFromSpecifier(getQuerySpecifier(item)), + updateQuery, + }; +} +/** + * Creates a function that performs an action while telling it about the + * optimistic updates it caused. + * + * @param actionFn The Wasp Action. + * @param optimisticUpdateDefinitions The optimisitc updates the action causes. + * @returns An decorated action which performs optimistic updates. + */ +function makeOptimisticUpdateMutationFn(actionFn, optimisticUpdateDefinitions) { + return function performActionWithOptimisticUpdates(item) { + const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map((generalDefinition) => getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)); + return actionFn.internal(item, specificOptimisticUpdateDefinitions); + }; +} +/** + * Given a ReactQuery query client and our internal definition of optimistic + * updates, this function constructs an object describing those same optimistic + * updates in a format we can pass into React Query's useMutation hook. In other + * words, it translates our optimistic updates definition into React Query's + * optimistic updates definition. Check their docs for details: + * https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates + * + * @param queryClient The QueryClient instance used by React Query. + * @param optimisticUpdateDefinitions A list containing internal optimistic + * updates definition objects (i.e., a list where each object carries the + * instructions for performing particular optimistic update). + * @returns An object containing 'onMutate' and 'onError' functions + * corresponding to the given optimistic update definitions (check the docs + * linked above for details). + */ +function makeRqOptimisticUpdateOptions(queryClient, optimisticUpdateDefinitions) { + async function onMutate(item) { + const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map((generalDefinition) => getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)); + // Cancel any outgoing refetches (so they don't overwrite our optimistic update). + // Theoretically, we can be a bit faster. Instead of awaiting the + // cancellation of all queries, we could cancel and update them in parallel. + // However, awaiting cancellation hasn't yet proven to be a performance bottleneck. + await Promise.all(specificOptimisticUpdateDefinitions.map(({ queryKey }) => queryClient.cancelQueries(queryKey))); + // We're using a Map to correctly serialize query keys that contain objects. + const previousData = new Map(); + specificOptimisticUpdateDefinitions.forEach(({ queryKey, updateQuery }) => { + // Snapshot the currently cached value. + const previousDataForQuery = queryClient.getQueryData(queryKey); + // Attempt to optimistically update the cache using the new value. + try { + queryClient.setQueryData(queryKey, updateQuery); + } + catch (e) { + console.error("The `updateQuery` function threw an exception, skipping optimistic update:"); + console.error(e); + } + // Remember the snapshotted value to restore in case of an error. + previousData.set(queryKey, previousDataForQuery); + }); + return { previousData }; + } + function onError(_err, _item, context) { + // All we do in case of an error is roll back all optimistic updates. We ensure + // not to do anything else because React Query rethrows the error. This allows + // the programmer to handle the error as they usually would (i.e., we want the + // error handling to work as it would if the programmer wasn't using optimistic + // updates). + context.previousData.forEach(async (data, queryKey) => { + await queryClient.cancelQueries(queryKey); + queryClient.setQueryData(queryKey, data); + }); + } + return { + onMutate, + onError, + }; +} +/** + * Constructs the definition for optimistically updating a specific item. It + * uses a closure over the updated item to construct an item-specific query key + * (e.g., useful when the query key depends on an ID). + * + * @param optimisticUpdateDefinition The general, "uninstantiated" optimistic + * update definition with a function for constructing the query key. + * @param item The item triggering the Action/optimistic update (i.e., the + * argument passed to the Action). + * @returns A specific optimistic update definition which corresponds to the + * provided definition and closes over the provided item. + */ +function getOptimisticUpdateDefinitionForSpecificItem(optimisticUpdateDefinition, item) { + const { getQueryKey, updateQuery } = optimisticUpdateDefinition; + return { + queryKey: getQueryKey(item), + updateQuery: (old) => updateQuery(item, old), + }; +} +/** + * Translates a Wasp query specifier to a query cache key used by React Query. + * + * @param querySpecifier A query specifier that's a part of the public API: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + * @returns A cache key React Query internally uses for addressing queries. + */ +function getRqQueryKeyFromSpecifier(querySpecifier) { + const [queryFn, ...otherKeys] = querySpecifier; + return [...queryFn.queryCacheKey, ...otherKeys]; +} +//# sourceMappingURL=hooks.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map new file mode 100644 index 0000000000..9048c71ee2 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../client/operations/hooks.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts index 301165fa8e..76ad094f0d 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts @@ -1,4 +1,4 @@ export * from './actions'; export * from './queries'; -export { useAction, useQuery, type OptimisticUpdateDefinition, } from './core'; +export { useAction, useQuery, type OptimisticUpdateDefinition, } from './hooks'; export { configureQueryClient, initializeQueryClient, queryClientInitialized } from './queryClient'; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js index f83307c7b1..fd2c6b29b0 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js @@ -6,7 +6,7 @@ export { // PUBLIC API useAction, // PUBLIC API -useQuery, } from './core'; +useQuery, } from './hooks'; export { // PUBLIC API configureQueryClient, diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js.map index 982c957a9a..a6cf9161ab 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,QAAQ,CAAA;AAEf,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,SAAS,CAAA;AAEhB,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts index 93bbd1ddaa..c70de80ba6 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts @@ -1,12 +1,25 @@ import { Route } from 'wasp/client'; -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Query } from '../core.js'; -export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; -export declare function addMetadataToQuery(query: (...args: any[]) => Promise, metadata: { - relativeQueryPath: string; +import type { GenericBackendOperation, GenericOperationRpc, OperationRpcFor, Query, QueryMetadata } from '../rpc.js'; +export declare function makeQueryCacheKey(query: Query, payload: Input): (string | Input)[]; +export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; +export declare function buildAndRegisterQuery(queryFn: QF, { queryCacheKey, queryRoute, entitiesUsed }: { + queryCacheKey: string[]; queryRoute: Route; entitiesUsed: string[]; -}): void; -export type QueryFor = Query[0], _Awaited<_ReturnType>>; -type GenericBackendQuery = (args: never, context: any) => unknown; +}): QueryForFunction; +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = QueryForFunction>; +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = OperationRpcFor; +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata; export {}; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js index c03f172443..fefdfc58fc 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js @@ -1,18 +1,28 @@ import { callOperation, makeOperationRoute } from '../internal/index.js'; import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources'; +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey(query, payload) { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey; +} +// PRIVATE API (unsed in SDK) export function createQuery(relativeQueryPath, entitiesUsed) { const queryRoute = makeOperationRoute(relativeQueryPath); - async function query(queryKey, queryArgs) { + const queryCacheKey = [relativeQueryPath]; + const queryFn = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs); - return getActiveOptimisticUpdates(queryKey).reduce((result, update) => update(result), serverResult); - } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }); - return query; + const queryCacheKey = makeQueryCacheKey(queryFn, queryArgs); + return getActiveOptimisticUpdates(queryCacheKey).reduce((result, update) => update(result), serverResult); + }; + return buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }); } -// PRIVATE API -export function addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) { - query.queryCacheKey = [relativeQueryPath]; +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }) { + const query = queryFn; + query.queryCacheKey = queryCacheKey; query.route = queryRoute; addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed); + return query; } //# sourceMappingURL=core.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map index dcc40d2693..0ef0547c44 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IAExD,KAAK,UAAU,KAAK,CAAC,QAAQ,EAAE,SAAS;QACtC,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,OAAO,0BAA0B,CAAC,QAAQ,CAAC,CAAC,MAAM,CAChD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAA;IAE1E,OAAO,KAAK,CAAA;AACd,CAAC;AAYD,cAAc;AACd,MAAM,UAAU,kBAAkB,CAChC,KAAK,EACL,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE;IAE/C,KAAK,CAAC,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IACzC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;AAC5D,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,gCAAgC;AAChC,MAAM,UAAU,iBAAiB,CAC/B,KAA2B,EAC3B,OAAc;IAEd,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC;QAC5B,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,aAAa,CAAA;AAC3B,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IACxD,MAAM,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAEzC,MAAM,OAAO,GAAmC,KAAK,EAAE,SAAS,EAAE,EAAE;QAClE,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,MAAM,aAAa,GAAG,iBAAiB,CAAC,OAAiC,EAAE,SAAS,CAAC,CAAA;QACrF,OAAO,0BAA0B,CAAC,aAAa,CAAC,CAAC,MAAM,CACrD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC,CAAA;IAED,OAAO,qBAAqB,CAC1B,OAAO,EACP,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,CAC5C,CAAA;AACH,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,qBAAqB,CACnC,OAAW,EACX,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAC6B;IAEtE,MAAM,KAAK,GAAG,OAA+B,CAAA;IAE7C,KAAK,CAAC,aAAa,GAAG,aAAa,CAAA;IACnC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IAE1D,OAAO,KAAK,CAAA;AACd,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts index 575c502be1..2d9dbafe81 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts @@ -1 +1 @@ -export { addMetadataToQuery } from './core'; +export { buildAndRegisterQuery } from './core'; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js index 1c28e8d0d3..56d2e15238 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js @@ -1,3 +1,3 @@ -// PRIVATE API -export { addMetadataToQuery } from './core'; +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map index 5c83611fa3..44416efcfa 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts new file mode 100644 index 0000000000..ee52ec65b4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts @@ -0,0 +1,38 @@ +import { type Route } from "wasp/client"; +import type { _Awaited, _ReturnType } from "wasp/universal/types"; +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata; +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation; +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation; +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[]; + route: Route; +}; +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = Parameters extends [] ? ClientOperation>> : ClientOperation[0], _Awaited<_ReturnType>>; +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown; +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise; +type ClientOperation = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export {}; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js new file mode 100644 index 0000000000..f3a500abe4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=rpc.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map new file mode 100644 index 0000000000..a51bf309e5 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../client/operations/rpc.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts index 645112861a..89fd0d7587 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts @@ -1,7 +1,7 @@ import { ReactElement } from 'react'; import { type SetupServer } from 'msw/node'; import { RenderResult } from '@testing-library/react'; -import { Query } from 'wasp/client/operations/core'; +import { Query } from 'wasp/client/operations/rpc'; import { Route } from 'wasp/client'; export type MockQuery = (query: Query, resJson: MockOutput) => void; export type MockApi = (route: Route, resJson: unknown) => void; diff --git a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/package.json index b46249ed12..2a7a874c5c 100644 --- a/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspJob-golden/waspJob/.wasp/out/sdk/wasp/package.json @@ -42,7 +42,7 @@ "./client/auth": "./dist/client/auth/index.js", "./client/crud": "./dist/client/crud/index.js", "./client/operations": "./dist/client/operations/index.js", - "./client/operations/core": "./dist/client/operations/core.js", + "./client/operations/rpc": "./dist/client/operations/rpc.js", "./client/router": "./dist/client/router/index.js", "./client/test": "./dist/client/test/index.js", "./client/test/*": "./dist/client/test/*.js", diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/files.manifest b/waspc/e2e-test/test-outputs/waspMigrate-golden/files.manifest index 3a96de88a7..37cd0f2f45 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/files.manifest +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/files.manifest @@ -13,7 +13,7 @@ waspMigrate/.wasp/out/sdk/wasp/client/config.ts waspMigrate/.wasp/out/sdk/wasp/client/index.ts waspMigrate/.wasp/out/sdk/wasp/client/operations/actions/core.ts waspMigrate/.wasp/out/sdk/wasp/client/operations/actions/index.ts -waspMigrate/.wasp/out/sdk/wasp/client/operations/core.ts +waspMigrate/.wasp/out/sdk/wasp/client/operations/hooks.ts waspMigrate/.wasp/out/sdk/wasp/client/operations/index.ts waspMigrate/.wasp/out/sdk/wasp/client/operations/internal/index.ts waspMigrate/.wasp/out/sdk/wasp/client/operations/internal/resources.js @@ -21,6 +21,7 @@ waspMigrate/.wasp/out/sdk/wasp/client/operations/internal/updateHandlersMap.js waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/core.ts waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/index.ts waspMigrate/.wasp/out/sdk/wasp/client/operations/queryClient.ts +waspMigrate/.wasp/out/sdk/wasp/client/operations/rpc.ts waspMigrate/.wasp/out/sdk/wasp/client/router/Link.tsx waspMigrate/.wasp/out/sdk/wasp/client/router/index.ts waspMigrate/.wasp/out/sdk/wasp/client/router/linkHelpers.ts @@ -47,9 +48,9 @@ waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/core.js.map waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/index.d.ts waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/index.js.map -waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts -waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js -waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts +waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js +waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -71,6 +72,9 @@ waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queryClient.d.ts waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queryClient.js.map +waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts +waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js +waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map waspMigrate/.wasp/out/sdk/wasp/dist/client/router/Link.d.ts waspMigrate/.wasp/out/sdk/wasp/dist/client/router/Link.jsx waspMigrate/.wasp/out/sdk/wasp/dist/client/router/Link.jsx.map diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums index 7a506f253c..e7b562f887 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/.waspchecksums @@ -32,7 +32,7 @@ "file", "../out/sdk/wasp/client/operations/actions/core.ts" ], - "016623c0ebdc1b88d746fa1345015b3cb9653429abdc13a9147a952bff83a927" + "d19dba04947e4015af69d90dd160ec5f4ed020bfa905bc37bcd5d980517097ae" ], [ [ @@ -44,16 +44,16 @@ [ [ "file", - "../out/sdk/wasp/client/operations/core.ts" + "../out/sdk/wasp/client/operations/hooks.ts" ], - "bad860771b16a0d4830fab22de8b85e63c840d47dc3728728a23b8ada91061ef" + "eb4362162aad4b605781e2e33facef83935a7df4101cc0a77097ceaff3a0b360" ], [ [ "file", "../out/sdk/wasp/client/operations/index.ts" ], - "4a66c90319dd7ef0d3a8e6c1f571037c7dfd9778b9def6e951813dbc4b4dcef3" + "edcdc3798590e62b778115b3818df8cc69fa5a8bb3a7fe9fa6d6d5ea706d14c4" ], [ [ @@ -81,14 +81,14 @@ "file", "../out/sdk/wasp/client/operations/queries/core.ts" ], - "5f30328d93582f9c8444720e99f45c19c8647f052b7fbcf5f71b578b9241ac96" + "cce982751b463494c048efd683dddb8d4e617d2f354722a79961199990c7201a" ], [ [ "file", "../out/sdk/wasp/client/operations/queries/index.ts" ], - "882410504b909cc421d50a27c39952f664ba3457438ce746a95d9cab3431944c" + "c92c64425986a38f835211c2693380a8b13904cb78bbf6f6ae880e56ade51686" ], [ [ @@ -97,6 +97,13 @@ ], "5c1d87ac10513788bcde7ebc7c10601b9ad0854cddff355e8fb7e2d4685ecdef" ], + [ + [ + "file", + "../out/sdk/wasp/client/operations/rpc.ts" + ], + "5ab471422e7916c33a0931ce8d499d7d40191802ce2c6f3343b45c623a963566" + ], [ [ "file", @@ -137,7 +144,7 @@ "file", "../out/sdk/wasp/client/test/vitest/helpers.tsx" ], - "b2362e8f80134137fda2f8bb43ef7c0d7ae8aadf8a7adfa472d42d6699e9d918" + "b44ff591a2eebfff4de9fa9e9e1b89f1f22f523f03ab0febc19ff3999721b39a" ], [ [ @@ -193,7 +200,7 @@ "file", "../out/sdk/wasp/package.json" ], - "3422dd87e9e5f4aeb3922ee152ad691399d91ad71172f2b76f6235eb28955fa2" + "8df2ebcc130b484aa956ddf0109b23c83fe2221cb41ea35ed5e99817013f36a9" ], [ [ diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/actions/core.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/actions/core.ts index f5db25aff2..c24f726ef3 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/actions/core.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/actions/core.ts @@ -1,5 +1,5 @@ -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Action } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { registerActionInProgress, @@ -7,7 +7,7 @@ import { } from '../internal/resources.js' // PRIVATE API -export function createAction( +export function createAction( relativeActionRoute: string, entitiesUsed: unknown[] ): ActionFor { @@ -41,8 +41,5 @@ export function createAction( } // PRIVATE API -export type ActionFor = - Action[0], _Awaited<_ReturnType>> - - -type GenericBackendAction = (args: never, context: any) => unknown +export type ActionFor = + OperationRpcFor diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/core.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/core.ts deleted file mode 100644 index 282c4698a7..0000000000 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/core.ts +++ /dev/null @@ -1,346 +0,0 @@ -import { - QueryClient, - QueryKey, - useMutation, - UseMutationOptions, - useQueryClient, - useQuery as rqUseQuery, - UseQueryResult, -} from "@tanstack/react-query"; -export { configureQueryClient } from "./queryClient"; - -// PRIVATE API (but should maybe be public, users use values of this type) -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; - -// PUBLIC API -export function useQuery( - queryFn: Query, - queryFnArgs?: Input, - options?: any -): UseQueryResult; - -// PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); - } - if (!queryFn.queryCacheKey) { - throw new TypeError( - "queryFn needs to have queryCacheKey property defined." - ); - } - - const queryKey = - queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; - return rqUseQuery({ - queryKey, - queryFn: () => queryFn(queryKey, queryFnArgs), - ...options, - }); -} - -// PRIVATE API (but should maybe be public, users use values of this type) -export type Action = [Input] extends [never] - ? (args?: unknown) => Promise - : (args: Input) => Promise; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. - * - */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; - -// PUBLIC API -/** - * A documented (public) way to define optimistic updates. - */ -export type OptimisticUpdateDefinition = { - getQuerySpecifier: GetQuerySpecifier; - updateQuery: UpdateQuery; -}; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and returns a Wasp Query specifier. - */ -export type GetQuerySpecifier = ( - item: ActionInput -) => QuerySpecifier; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A function that takes an item and the previous state of the cache, and returns - * the desired (new) state of the cache. - */ -export type UpdateQuery = ( - item: ActionInput, - oldData: CachedData | undefined -) => CachedData; - -// PRIVATE API (but should maybe be public, users define values of this type) -/** - * A public query specifier used for addressing Wasp queries. See our docs for details: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - */ -export type QuerySpecifier = [Query, ...any[]]; - -// PUBLIC API -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export function useAction( - actionFn: Action, - actionOptions?: ActionOptions -): typeof actionFn { - const queryClient = useQueryClient(); - - let mutationFn = actionFn; - let options = {}; - if (actionOptions?.optimisticUpdates) { - const optimisticUpdatesDefinitions = actionOptions.optimisticUpdates.map( - translateToInternalDefinition - ); - mutationFn = makeOptimisticUpdateMutationFn( - actionFn, - optimisticUpdatesDefinitions - ); - options = makeRqOptimisticUpdateOptions( - queryClient, - optimisticUpdatesDefinitions - ); - } - - // NOTE: We decided to hide React Query's extra mutation features (e.g., - // isLoading, onSuccess and onError callbacks, synchronous mutate) and only - // expose a simple async function whose API matches the original Action. - // We did this to avoid cluttering the API with stuff we're not sure we need - // yet (e.g., isLoading), to postpone the action vs mutation dilemma, and to - // clearly separate our opinionated API from React Query's lower-level - // advanced API (which users can also use) - const mutation = useMutation(mutationFn, options); - return (args) => mutation.mutateAsync(args); -} - -/** - * An internal (undocumented, private, desugared) way of defining optimistic updates. - */ -type InternalOptimisticUpdateDefinition = { - getQueryKey: (item: ActionInput) => QueryKey; - updateQuery: UpdateQuery; -}; - -/** - * An UpdateQuery function "instantiated" with a specific item. It only takes - * the current state of the cache and returns the desired (new) state of the - * cache. - */ -type SpecificUpdateQuery = (oldData: CachedData) => CachedData; - -/** - * A specific, "instantiated" optimistic update definition which contains a - * fully-constructed query key and a specific update function. - */ -type SpecificOptimisticUpdateDefinition = { - queryKey: QueryKey; - updateQuery: SpecificUpdateQuery; -}; - -type InternalAction = Action & { - internal( - item: Input, - optimisticUpdateDefinitions: SpecificOptimisticUpdateDefinition[] - ): Promise; -}; - -/** - * Translates/Desugars a public optimistic update definition object into a - * definition object our system uses internally. - * - * @param publicOptimisticUpdateDefinition An optimistic update definition - * object that's a part of the public API: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - * @returns An internally-used optimistic update definition object. - */ -function translateToInternalDefinition( - publicOptimisticUpdateDefinition: OptimisticUpdateDefinition -): InternalOptimisticUpdateDefinition { - const { getQuerySpecifier, updateQuery } = publicOptimisticUpdateDefinition; - - const definitionErrors = []; - if (typeof getQuerySpecifier !== "function") { - definitionErrors.push("`getQuerySpecifier` is not a function."); - } - if (typeof updateQuery !== "function") { - definitionErrors.push("`updateQuery` is not a function."); - } - if (definitionErrors.length) { - throw new TypeError( - `Invalid optimistic update definition: ${definitionErrors.join(", ")}.` - ); - } - - return { - getQueryKey: (item) => getRqQueryKeyFromSpecifier(getQuerySpecifier(item)), - updateQuery, - }; -} - -/** - * Creates a function that performs an action while telling it about the - * optimistic updates it caused. - * - * @param actionFn The Wasp Action. - * @param optimisticUpdateDefinitions The optimisitc updates the action causes. - * @returns An decorated action which performs optimistic updates. - */ -function makeOptimisticUpdateMutationFn( - actionFn: Action, - optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition< - Input, - CachedData - >[] -): typeof actionFn { - return function performActionWithOptimisticUpdates(item) { - const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map( - (generalDefinition) => - getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item) - ); - return (actionFn as InternalAction).internal( - item, - specificOptimisticUpdateDefinitions - ); - }; -} - -/** - * Given a ReactQuery query client and our internal definition of optimistic - * updates, this function constructs an object describing those same optimistic - * updates in a format we can pass into React Query's useMutation hook. In other - * words, it translates our optimistic updates definition into React Query's - * optimistic updates definition. Check their docs for details: - * https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates - * - * @param queryClient The QueryClient instance used by React Query. - * @param optimisticUpdateDefinitions A list containing internal optimistic - * updates definition objects (i.e., a list where each object carries the - * instructions for performing particular optimistic update). - * @returns An object containing 'onMutate' and 'onError' functions - * corresponding to the given optimistic update definitions (check the docs - * linked above for details). - */ -function makeRqOptimisticUpdateOptions( - queryClient: QueryClient, - optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition< - ActionInput, - CachedData - >[] -): Pick { - async function onMutate(item) { - const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map( - (generalDefinition) => - getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item) - ); - - // Cancel any outgoing refetches (so they don't overwrite our optimistic update). - // Theoretically, we can be a bit faster. Instead of awaiting the - // cancellation of all queries, we could cancel and update them in parallel. - // However, awaiting cancellation hasn't yet proven to be a performance bottleneck. - await Promise.all( - specificOptimisticUpdateDefinitions.map(({ queryKey }) => - queryClient.cancelQueries(queryKey) - ) - ); - - // We're using a Map to correctly serialize query keys that contain objects. - const previousData = new Map(); - specificOptimisticUpdateDefinitions.forEach(({ queryKey, updateQuery }) => { - // Snapshot the currently cached value. - const previousDataForQuery: CachedData = - queryClient.getQueryData(queryKey); - - // Attempt to optimistically update the cache using the new value. - try { - queryClient.setQueryData(queryKey, updateQuery); - } catch (e) { - console.error( - "The `updateQuery` function threw an exception, skipping optimistic update:" - ); - console.error(e); - } - - // Remember the snapshotted value to restore in case of an error. - previousData.set(queryKey, previousDataForQuery); - }); - - return { previousData }; - } - - function onError(_err, _item, context) { - // All we do in case of an error is roll back all optimistic updates. We ensure - // not to do anything else because React Query rethrows the error. This allows - // the programmer to handle the error as they usually would (i.e., we want the - // error handling to work as it would if the programmer wasn't using optimistic - // updates). - context.previousData.forEach(async (data, queryKey) => { - await queryClient.cancelQueries(queryKey); - queryClient.setQueryData(queryKey, data); - }); - } - - return { - onMutate, - onError, - }; -} - -/** - * Constructs the definition for optimistically updating a specific item. It - * uses a closure over the updated item to construct an item-specific query key - * (e.g., useful when the query key depends on an ID). - * - * @param optimisticUpdateDefinition The general, "uninstantiated" optimistic - * update definition with a function for constructing the query key. - * @param item The item triggering the Action/optimistic update (i.e., the - * argument passed to the Action). - * @returns A specific optimistic update definition which corresponds to the - * provided definition and closes over the provided item. - */ -function getOptimisticUpdateDefinitionForSpecificItem( - optimisticUpdateDefinition: InternalOptimisticUpdateDefinition< - ActionInput, - CachedData - >, - item: ActionInput -): SpecificOptimisticUpdateDefinition { - const { getQueryKey, updateQuery } = optimisticUpdateDefinition; - return { - queryKey: getQueryKey(item), - updateQuery: (old) => updateQuery(item, old), - }; -} - -/** - * Translates a Wasp query specifier to a query cache key used by React Query. - * - * @param querySpecifier A query specifier that's a part of the public API: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - * @returns A cache key React Query internally uses for addressing queries. - */ -function getRqQueryKeyFromSpecifier( - querySpecifier: QuerySpecifier -): QueryKey { - const [queryFn, ...otherKeys] = querySpecifier; - return [...(queryFn as any).queryCacheKey, ...otherKeys]; -} diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/hooks.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/hooks.ts new file mode 100644 index 0000000000..fa913a44c1 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/hooks.ts @@ -0,0 +1,328 @@ +import { + QueryClient, + QueryKey, + useMutation, + UseMutationOptions, + useQueryClient, + useQuery as rqUseQuery, + UseQueryResult, +} from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; +import { makeQueryCacheKey } from "./queries/core"; +export { configureQueryClient } from "./queryClient"; + +// PUBLIC API +export function useQuery( + query: Query, + queryFnArgs?: Input, + options?: any +): UseQueryResult { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.') + } + + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.') + } + + return rqUseQuery({ + queryKey: makeQueryCacheKey(query, queryFnArgs), + queryFn: () => query(queryFnArgs), + ...options, + }) +} + +// PUBLIC API +/** + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). + * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. + */ +export function useAction( + actionFn: Action, + actionOptions?: ActionOptions +): typeof actionFn { + const queryClient = useQueryClient(); + + let mutationFn = actionFn; + let options = {}; + if (actionOptions?.optimisticUpdates) { + const optimisticUpdatesDefinitions = actionOptions.optimisticUpdates.map( + translateToInternalDefinition + ); + mutationFn = makeOptimisticUpdateMutationFn( + actionFn, + optimisticUpdatesDefinitions + ); + options = makeRqOptimisticUpdateOptions( + queryClient, + optimisticUpdatesDefinitions + ); + } + + // NOTE: We decided to hide React Query's extra mutation features (e.g., + // isLoading, onSuccess and onError callbacks, synchronous mutate) and only + // expose a simple async function whose API matches the original Action. + // We did this to avoid cluttering the API with stuff we're not sure we need + // yet (e.g., isLoading), to postpone the action vs mutation dilemma, and to + // clearly separate our opinionated API from React Query's lower-level + // advanced API (which users can also use) + const mutation = useMutation(mutationFn, options); + return (args) => mutation.mutateAsync(args); +} + +// PUBLIC API +/** + * A documented (public) way to define optimistic updates. + */ +export type OptimisticUpdateDefinition = { + getQuerySpecifier: GetQuerySpecifier; + updateQuery: UpdateQuery; +}; + +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; + +/** + * A function that takes an item and returns a Wasp Query specifier. + */ +type GetQuerySpecifier = ( + item: ActionInput +) => QuerySpecifier; + +/** + * A function that takes an item and the previous state of the cache, and returns + * the desired (new) state of the cache. + */ +type UpdateQuery = ( + item: ActionInput, + oldData: CachedData | undefined +) => CachedData; + +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * A public query specifier used for addressing Wasp queries. See our docs for details: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + */ +type QuerySpecifier = [Query, ...any[]]; + + +/** + * An internal (undocumented, private, desugared) way of defining optimistic updates. + */ +type InternalOptimisticUpdateDefinition = { + getQueryKey: (item: ActionInput) => QueryKey; + updateQuery: UpdateQuery; +}; + +/** + * An UpdateQuery function "instantiated" with a specific item. It only takes + * the current state of the cache and returns the desired (new) state of the + * cache. + */ +type SpecificUpdateQuery = (oldData: CachedData) => CachedData; + +/** + * A specific, "instantiated" optimistic update definition which contains a + * fully-constructed query key and a specific update function. + */ +type SpecificOptimisticUpdateDefinition = { + queryKey: QueryKey; + updateQuery: SpecificUpdateQuery; +}; + +type InternalAction = Action & { + internal( + item: Input, + optimisticUpdateDefinitions: SpecificOptimisticUpdateDefinition[] + ): Promise; +}; + +/** + * Translates/Desugars a public optimistic update definition object into a + * definition object our system uses internally. + * + * @param publicOptimisticUpdateDefinition An optimistic update definition + * object that's a part of the public API: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + * @returns An internally-used optimistic update definition object. + */ +function translateToInternalDefinition( + publicOptimisticUpdateDefinition: OptimisticUpdateDefinition +): InternalOptimisticUpdateDefinition { + const { getQuerySpecifier, updateQuery } = publicOptimisticUpdateDefinition; + + const definitionErrors = []; + if (typeof getQuerySpecifier !== "function") { + definitionErrors.push("`getQuerySpecifier` is not a function."); + } + if (typeof updateQuery !== "function") { + definitionErrors.push("`updateQuery` is not a function."); + } + if (definitionErrors.length) { + throw new TypeError( + `Invalid optimistic update definition: ${definitionErrors.join(", ")}.` + ); + } + + return { + getQueryKey: (item) => getRqQueryKeyFromSpecifier(getQuerySpecifier(item)), + updateQuery, + }; +} + +/** + * Creates a function that performs an action while telling it about the + * optimistic updates it caused. + * + * @param actionFn The Wasp Action. + * @param optimisticUpdateDefinitions The optimisitc updates the action causes. + * @returns An decorated action which performs optimistic updates. + */ +function makeOptimisticUpdateMutationFn( + actionFn: Action, + optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition< + Input, + CachedData + >[] +): typeof actionFn { + return function performActionWithOptimisticUpdates(item) { + const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map( + (generalDefinition) => + getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item) + ); + return (actionFn as InternalAction).internal( + item, + specificOptimisticUpdateDefinitions + ); + }; +} + +/** + * Given a ReactQuery query client and our internal definition of optimistic + * updates, this function constructs an object describing those same optimistic + * updates in a format we can pass into React Query's useMutation hook. In other + * words, it translates our optimistic updates definition into React Query's + * optimistic updates definition. Check their docs for details: + * https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates + * + * @param queryClient The QueryClient instance used by React Query. + * @param optimisticUpdateDefinitions A list containing internal optimistic + * updates definition objects (i.e., a list where each object carries the + * instructions for performing particular optimistic update). + * @returns An object containing 'onMutate' and 'onError' functions + * corresponding to the given optimistic update definitions (check the docs + * linked above for details). + */ +function makeRqOptimisticUpdateOptions( + queryClient: QueryClient, + optimisticUpdateDefinitions: InternalOptimisticUpdateDefinition< + ActionInput, + CachedData + >[] +): Pick { + async function onMutate(item) { + const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map( + (generalDefinition) => + getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item) + ); + + // Cancel any outgoing refetches (so they don't overwrite our optimistic update). + // Theoretically, we can be a bit faster. Instead of awaiting the + // cancellation of all queries, we could cancel and update them in parallel. + // However, awaiting cancellation hasn't yet proven to be a performance bottleneck. + await Promise.all( + specificOptimisticUpdateDefinitions.map(({ queryKey }) => + queryClient.cancelQueries(queryKey) + ) + ); + + // We're using a Map to correctly serialize query keys that contain objects. + const previousData = new Map(); + specificOptimisticUpdateDefinitions.forEach(({ queryKey, updateQuery }) => { + // Snapshot the currently cached value. + const previousDataForQuery: CachedData = + queryClient.getQueryData(queryKey); + + // Attempt to optimistically update the cache using the new value. + try { + queryClient.setQueryData(queryKey, updateQuery); + } catch (e) { + console.error( + "The `updateQuery` function threw an exception, skipping optimistic update:" + ); + console.error(e); + } + + // Remember the snapshotted value to restore in case of an error. + previousData.set(queryKey, previousDataForQuery); + }); + + return { previousData }; + } + + function onError(_err, _item, context) { + // All we do in case of an error is roll back all optimistic updates. We ensure + // not to do anything else because React Query rethrows the error. This allows + // the programmer to handle the error as they usually would (i.e., we want the + // error handling to work as it would if the programmer wasn't using optimistic + // updates). + context.previousData.forEach(async (data, queryKey) => { + await queryClient.cancelQueries(queryKey); + queryClient.setQueryData(queryKey, data); + }); + } + + return { + onMutate, + onError, + }; +} + +/** + * Constructs the definition for optimistically updating a specific item. It + * uses a closure over the updated item to construct an item-specific query key + * (e.g., useful when the query key depends on an ID). + * + * @param optimisticUpdateDefinition The general, "uninstantiated" optimistic + * update definition with a function for constructing the query key. + * @param item The item triggering the Action/optimistic update (i.e., the + * argument passed to the Action). + * @returns A specific optimistic update definition which corresponds to the + * provided definition and closes over the provided item. + */ +function getOptimisticUpdateDefinitionForSpecificItem( + optimisticUpdateDefinition: InternalOptimisticUpdateDefinition< + ActionInput, + CachedData + >, + item: ActionInput +): SpecificOptimisticUpdateDefinition { + const { getQueryKey, updateQuery } = optimisticUpdateDefinition; + return { + queryKey: getQueryKey(item), + updateQuery: (old) => updateQuery(item, old), + }; +} + +/** + * Translates a Wasp query specifier to a query cache key used by React Query. + * + * @param querySpecifier A query specifier that's a part of the public API: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + * @returns A cache key React Query internally uses for addressing queries. + */ +function getRqQueryKeyFromSpecifier( + querySpecifier: QuerySpecifier +): QueryKey { + const [queryFn, ...otherKeys] = querySpecifier; + return [...(queryFn as any).queryCacheKey, ...otherKeys]; +} diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/index.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/index.ts index ec9ca9f689..4dc2691035 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/index.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/index.ts @@ -10,7 +10,7 @@ export { useQuery, // PUBLIC API type OptimisticUpdateDefinition, -} from './core' +} from './hooks' export { // PUBLIC API diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/core.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/core.ts index bdc0a9db75..36cd6ad067 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/core.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/core.ts @@ -1,53 +1,83 @@ import { Route } from 'wasp/client' -import type { Expand, _Awaited, _ReturnType } from 'wasp/universal/types' -import { type Query } from '../core.js' +import type { _Awaited, _ReturnType } from 'wasp/universal/types' +import type { + GenericBackendOperation, + GenericOperationRpc, + OperationRpcFor, + Query, + QueryMetadata, +} from '../rpc.js' import { callOperation, makeOperationRoute } from '../internal/index.js' import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources' -export function createQuery( +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey( + query: Query, + payload: Input +): (string | Input)[] { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey +} + +// PRIVATE API (unsed in SDK) +export function createQuery( relativeQueryPath: string, entitiesUsed: string[] ): QueryFor { const queryRoute = makeOperationRoute(relativeQueryPath) + const queryCacheKey = [relativeQueryPath] - async function query(queryKey, queryArgs) { + const queryFn: QueryFunctionFor = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs) - return getActiveOptimisticUpdates(queryKey).reduce( + const queryCacheKey = makeQueryCacheKey(queryFn as QueryFor, queryArgs) + return getActiveOptimisticUpdates(queryCacheKey).reduce( (result, update) => update(result), serverResult, ) } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) - - return query + return buildAndRegisterQuery( + queryFn, + { queryCacheKey, queryRoute, entitiesUsed }, + ) } -// PRIVATE API -export function addMetadataToQuery( - query: (...args: any[]) => Promise, - metadata: { - relativeQueryPath: string - queryRoute: Route - entitiesUsed: string[] - } -): void - -// PRIVATE API -export function addMetadataToQuery( - query, - { relativeQueryPath, queryRoute, entitiesUsed } -) { - query.queryCacheKey = [relativeQueryPath] +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery( + queryFn: QF, + { queryCacheKey, queryRoute, entitiesUsed }: + { queryCacheKey: string[], queryRoute: Route, entitiesUsed: string[] } +): QueryForFunction { + const query = queryFn as QueryForFunction + + query.queryCacheKey = queryCacheKey query.route = queryRoute addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed) + + return query } -export type QueryFor = - Query[0], _Awaited<_ReturnType>> +// PRIVATE API (but should maybe be public, users define values of this type) +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = + QueryForFunction> +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = + OperationRpcFor -type GenericBackendQuery = (args: never, context: any) => unknown \ No newline at end of file +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/index.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/index.ts index eeb2cf5a11..af63c67c63 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/index.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/queries/index.ts @@ -1,4 +1,4 @@ import { type QueryFor, createQuery } from './core' -// PRIVATE API -export { addMetadataToQuery } from './core' +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core' diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/rpc.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/rpc.ts new file mode 100644 index 0000000000..45a8dbbf47 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/operations/rpc.ts @@ -0,0 +1,77 @@ +import { type Route } from "wasp/client"; +import type { + _Awaited, + _ReturnType, +} from "wasp/universal/types" + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type). +// +// Frontend queries are functions with some extra properties (metadata). +// +// To simplify working with the type (i.e., referencing the type's two different +// components), we've defined it as an intersection of two distinct types: +// one representing the function (QueryFunction), and the other representing the +// metadata (QueryMetadata) . +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata + +// PRIVATE API (for SDK, should maybe be public, users define values of this +// type) +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation + +// PRIVATE API (for SDK) +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation + +// PRIVATE API (for SDK) +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[] + route: Route +} + +// PRIVATE API (needed in SDK) +// Explanation: +// - Custom `_Awaited` and `_ReturnType` - Read the comments above their +// definitions. +// - `Parameters extends []` - See here: +// https://github.com/wasp-lang/wasp/pull/1992/files#r1583040080 +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = + Parameters extends [] + ? ClientOperation>> + : ClientOperation< + Parameters[0], + _Awaited<_ReturnType> + > + +// PRIVATE API (needed in SDK) +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown + +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise + +// Read this to understand the type: https://github.com/wasp-lang/wasp/pull/1090#discussion_r1159732471 +type ClientOperation = [Input] extends [never] + ? (args?: unknown) => Promise + : (args: Input) => Promise; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx index 8e6085f34c..96ff5e90e8 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/client/test/vitest/helpers.tsx @@ -6,7 +6,7 @@ import { BrowserRouter as Router } from 'react-router-dom' import { render, RenderResult, cleanup } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { beforeAll, afterEach, afterAll } from 'vitest' -import { Query } from 'wasp/client/operations/core' +import { Query } from 'wasp/client/operations/rpc' import { config } from 'wasp/client' import { HttpMethod, Route } from 'wasp/client' diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts index e1708451f8..4b8c455fd4 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/actions/core.d.ts @@ -1,6 +1,3 @@ -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Action } from '../core.js'; -export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; -export type ActionFor = Action[0], _Awaited<_ReturnType>>; -type GenericBackendAction = (args: never, context: any) => unknown; -export {}; +import type { OperationRpcFor, GenericBackendOperation } from '../rpc.js'; +export declare function createAction(relativeActionRoute: string, entitiesUsed: unknown[]): ActionFor; +export type ActionFor = OperationRpcFor; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts deleted file mode 100644 index a23b24ebd6..0000000000 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { UseQueryResult } from "@tanstack/react-query"; -export { configureQueryClient } from "./queryClient"; -export type Query = { - (queryCacheKey: string[], args: Input): Promise; -}; -export declare function useQuery(queryFn: Query, queryFnArgs?: Input, options?: any): UseQueryResult; -export type Action = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; -/** - * An options object passed into the `useAction` hook and used to enhance the - * action with extra options. - * - */ -export type ActionOptions = { - optimisticUpdates: OptimisticUpdateDefinition[]; -}; -/** - * A documented (public) way to define optimistic updates. - */ -export type OptimisticUpdateDefinition = { - getQuerySpecifier: GetQuerySpecifier; - updateQuery: UpdateQuery; -}; -/** - * A function that takes an item and returns a Wasp Query specifier. - */ -export type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; -/** - * A function that takes an item and the previous state of the cache, and returns - * the desired (new) state of the cache. - */ -export type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; -/** - * A public query specifier used for addressing Wasp queries. See our docs for details: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - */ -export type QuerySpecifier = [Query, ...any[]]; -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js deleted file mode 100644 index 2c94cb01fd..0000000000 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js +++ /dev/null @@ -1,171 +0,0 @@ -import { useMutation, useQueryClient, useQuery as rqUseQuery, } from "@tanstack/react-query"; -export { configureQueryClient } from "./queryClient"; -// PUBLIC API -export function useQuery(queryFn, queryFnArgs, options) { - if (typeof queryFn !== "function") { - throw new TypeError("useQuery requires queryFn to be a function."); - } - if (!queryFn.queryCacheKey) { - throw new TypeError("queryFn needs to have queryCacheKey property defined."); - } - const queryKey = queryFnArgs !== undefined - ? [...queryFn.queryCacheKey, queryFnArgs] - : queryFn.queryCacheKey; - return rqUseQuery(Object.assign({ queryKey, queryFn: () => queryFn(queryKey, queryFnArgs) }, options)); -} -// PUBLIC API -/** - * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). - * - * @param actionFn The Wasp Action you wish to enhance/decorate. - * @param actionOptions An options object for enhancing/decorating the given Action. - * @returns A decorated Action with added behavior but an unchanged API. - */ -export function useAction(actionFn, actionOptions) { - const queryClient = useQueryClient(); - let mutationFn = actionFn; - let options = {}; - if (actionOptions === null || actionOptions === void 0 ? void 0 : actionOptions.optimisticUpdates) { - const optimisticUpdatesDefinitions = actionOptions.optimisticUpdates.map(translateToInternalDefinition); - mutationFn = makeOptimisticUpdateMutationFn(actionFn, optimisticUpdatesDefinitions); - options = makeRqOptimisticUpdateOptions(queryClient, optimisticUpdatesDefinitions); - } - // NOTE: We decided to hide React Query's extra mutation features (e.g., - // isLoading, onSuccess and onError callbacks, synchronous mutate) and only - // expose a simple async function whose API matches the original Action. - // We did this to avoid cluttering the API with stuff we're not sure we need - // yet (e.g., isLoading), to postpone the action vs mutation dilemma, and to - // clearly separate our opinionated API from React Query's lower-level - // advanced API (which users can also use) - const mutation = useMutation(mutationFn, options); - return (args) => mutation.mutateAsync(args); -} -/** - * Translates/Desugars a public optimistic update definition object into a - * definition object our system uses internally. - * - * @param publicOptimisticUpdateDefinition An optimistic update definition - * object that's a part of the public API: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - * @returns An internally-used optimistic update definition object. - */ -function translateToInternalDefinition(publicOptimisticUpdateDefinition) { - const { getQuerySpecifier, updateQuery } = publicOptimisticUpdateDefinition; - const definitionErrors = []; - if (typeof getQuerySpecifier !== "function") { - definitionErrors.push("`getQuerySpecifier` is not a function."); - } - if (typeof updateQuery !== "function") { - definitionErrors.push("`updateQuery` is not a function."); - } - if (definitionErrors.length) { - throw new TypeError(`Invalid optimistic update definition: ${definitionErrors.join(", ")}.`); - } - return { - getQueryKey: (item) => getRqQueryKeyFromSpecifier(getQuerySpecifier(item)), - updateQuery, - }; -} -/** - * Creates a function that performs an action while telling it about the - * optimistic updates it caused. - * - * @param actionFn The Wasp Action. - * @param optimisticUpdateDefinitions The optimisitc updates the action causes. - * @returns An decorated action which performs optimistic updates. - */ -function makeOptimisticUpdateMutationFn(actionFn, optimisticUpdateDefinitions) { - return function performActionWithOptimisticUpdates(item) { - const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map((generalDefinition) => getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)); - return actionFn.internal(item, specificOptimisticUpdateDefinitions); - }; -} -/** - * Given a ReactQuery query client and our internal definition of optimistic - * updates, this function constructs an object describing those same optimistic - * updates in a format we can pass into React Query's useMutation hook. In other - * words, it translates our optimistic updates definition into React Query's - * optimistic updates definition. Check their docs for details: - * https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates - * - * @param queryClient The QueryClient instance used by React Query. - * @param optimisticUpdateDefinitions A list containing internal optimistic - * updates definition objects (i.e., a list where each object carries the - * instructions for performing particular optimistic update). - * @returns An object containing 'onMutate' and 'onError' functions - * corresponding to the given optimistic update definitions (check the docs - * linked above for details). - */ -function makeRqOptimisticUpdateOptions(queryClient, optimisticUpdateDefinitions) { - async function onMutate(item) { - const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map((generalDefinition) => getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)); - // Cancel any outgoing refetches (so they don't overwrite our optimistic update). - // Theoretically, we can be a bit faster. Instead of awaiting the - // cancellation of all queries, we could cancel and update them in parallel. - // However, awaiting cancellation hasn't yet proven to be a performance bottleneck. - await Promise.all(specificOptimisticUpdateDefinitions.map(({ queryKey }) => queryClient.cancelQueries(queryKey))); - // We're using a Map to correctly serialize query keys that contain objects. - const previousData = new Map(); - specificOptimisticUpdateDefinitions.forEach(({ queryKey, updateQuery }) => { - // Snapshot the currently cached value. - const previousDataForQuery = queryClient.getQueryData(queryKey); - // Attempt to optimistically update the cache using the new value. - try { - queryClient.setQueryData(queryKey, updateQuery); - } - catch (e) { - console.error("The `updateQuery` function threw an exception, skipping optimistic update:"); - console.error(e); - } - // Remember the snapshotted value to restore in case of an error. - previousData.set(queryKey, previousDataForQuery); - }); - return { previousData }; - } - function onError(_err, _item, context) { - // All we do in case of an error is roll back all optimistic updates. We ensure - // not to do anything else because React Query rethrows the error. This allows - // the programmer to handle the error as they usually would (i.e., we want the - // error handling to work as it would if the programmer wasn't using optimistic - // updates). - context.previousData.forEach(async (data, queryKey) => { - await queryClient.cancelQueries(queryKey); - queryClient.setQueryData(queryKey, data); - }); - } - return { - onMutate, - onError, - }; -} -/** - * Constructs the definition for optimistically updating a specific item. It - * uses a closure over the updated item to construct an item-specific query key - * (e.g., useful when the query key depends on an ID). - * - * @param optimisticUpdateDefinition The general, "uninstantiated" optimistic - * update definition with a function for constructing the query key. - * @param item The item triggering the Action/optimistic update (i.e., the - * argument passed to the Action). - * @returns A specific optimistic update definition which corresponds to the - * provided definition and closes over the provided item. - */ -function getOptimisticUpdateDefinitionForSpecificItem(optimisticUpdateDefinition, item) { - const { getQueryKey, updateQuery } = optimisticUpdateDefinition; - return { - queryKey: getQueryKey(item), - updateQuery: (old) => updateQuery(item, old), - }; -} -/** - * Translates a Wasp query specifier to a query cache key used by React Query. - * - * @param querySpecifier A query specifier that's a part of the public API: - * https://wasp-lang.dev/docs/language/features#the-useaction-hook. - * @returns A cache key React Query internally uses for addressing queries. - */ -function getRqQueryKeyFromSpecifier(querySpecifier) { - const [queryFn, ...otherKeys] = querySpecifier; - return [...queryFn.queryCacheKey, ...otherKeys]; -} -//# sourceMappingURL=core.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js.map deleted file mode 100644 index 20d72dc15e..0000000000 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/core.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../client/operations/core.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts new file mode 100644 index 0000000000..36a5e0b65b --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.d.ts @@ -0,0 +1,41 @@ +import { UseQueryResult } from "@tanstack/react-query"; +import { Action, Query } from "./rpc"; +export { configureQueryClient } from "./queryClient"; +export declare function useQuery(query: Query, queryFnArgs?: Input, options?: any): UseQueryResult; +/** + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). + * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. + */ +export declare function useAction(actionFn: Action, actionOptions?: ActionOptions): typeof actionFn; +/** + * A documented (public) way to define optimistic updates. + */ +export type OptimisticUpdateDefinition = { + getQuerySpecifier: GetQuerySpecifier; + updateQuery: UpdateQuery; +}; +/** + * An options object passed into the `useAction` hook and used to enhance the + * action with extra options. + * + */ +type ActionOptions = { + optimisticUpdates: OptimisticUpdateDefinition[]; +}; +/** + * A function that takes an item and returns a Wasp Query specifier. + */ +type GetQuerySpecifier = (item: ActionInput) => QuerySpecifier; +/** + * A function that takes an item and the previous state of the cache, and returns + * the desired (new) state of the cache. + */ +type UpdateQuery = (item: ActionInput, oldData: CachedData | undefined) => CachedData; +/** + * A public query specifier used for addressing Wasp queries. See our docs for details: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + */ +type QuerySpecifier = [Query, ...any[]]; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js new file mode 100644 index 0000000000..95ab379515 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js @@ -0,0 +1,169 @@ +import { useMutation, useQueryClient, useQuery as rqUseQuery, } from "@tanstack/react-query"; +import { makeQueryCacheKey } from "./queries/core"; +export { configureQueryClient } from "./queryClient"; +// PUBLIC API +export function useQuery(query, queryFnArgs, options) { + if (typeof query !== 'function') { + throw new TypeError('useQuery requires queryFn to be a function.'); + } + if (!query.queryCacheKey) { + throw new TypeError('queryFn needs to have queryCacheKey property defined.'); + } + return rqUseQuery(Object.assign({ queryKey: makeQueryCacheKey(query, queryFnArgs), queryFn: () => query(queryFnArgs) }, options)); +} +// PUBLIC API +/** + * A hook for adding extra behavior to a Wasp Action (e.g., optimistic updates). + * + * @param actionFn The Wasp Action you wish to enhance/decorate. + * @param actionOptions An options object for enhancing/decorating the given Action. + * @returns A decorated Action with added behavior but an unchanged API. + */ +export function useAction(actionFn, actionOptions) { + const queryClient = useQueryClient(); + let mutationFn = actionFn; + let options = {}; + if (actionOptions === null || actionOptions === void 0 ? void 0 : actionOptions.optimisticUpdates) { + const optimisticUpdatesDefinitions = actionOptions.optimisticUpdates.map(translateToInternalDefinition); + mutationFn = makeOptimisticUpdateMutationFn(actionFn, optimisticUpdatesDefinitions); + options = makeRqOptimisticUpdateOptions(queryClient, optimisticUpdatesDefinitions); + } + // NOTE: We decided to hide React Query's extra mutation features (e.g., + // isLoading, onSuccess and onError callbacks, synchronous mutate) and only + // expose a simple async function whose API matches the original Action. + // We did this to avoid cluttering the API with stuff we're not sure we need + // yet (e.g., isLoading), to postpone the action vs mutation dilemma, and to + // clearly separate our opinionated API from React Query's lower-level + // advanced API (which users can also use) + const mutation = useMutation(mutationFn, options); + return (args) => mutation.mutateAsync(args); +} +/** + * Translates/Desugars a public optimistic update definition object into a + * definition object our system uses internally. + * + * @param publicOptimisticUpdateDefinition An optimistic update definition + * object that's a part of the public API: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + * @returns An internally-used optimistic update definition object. + */ +function translateToInternalDefinition(publicOptimisticUpdateDefinition) { + const { getQuerySpecifier, updateQuery } = publicOptimisticUpdateDefinition; + const definitionErrors = []; + if (typeof getQuerySpecifier !== "function") { + definitionErrors.push("`getQuerySpecifier` is not a function."); + } + if (typeof updateQuery !== "function") { + definitionErrors.push("`updateQuery` is not a function."); + } + if (definitionErrors.length) { + throw new TypeError(`Invalid optimistic update definition: ${definitionErrors.join(", ")}.`); + } + return { + getQueryKey: (item) => getRqQueryKeyFromSpecifier(getQuerySpecifier(item)), + updateQuery, + }; +} +/** + * Creates a function that performs an action while telling it about the + * optimistic updates it caused. + * + * @param actionFn The Wasp Action. + * @param optimisticUpdateDefinitions The optimisitc updates the action causes. + * @returns An decorated action which performs optimistic updates. + */ +function makeOptimisticUpdateMutationFn(actionFn, optimisticUpdateDefinitions) { + return function performActionWithOptimisticUpdates(item) { + const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map((generalDefinition) => getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)); + return actionFn.internal(item, specificOptimisticUpdateDefinitions); + }; +} +/** + * Given a ReactQuery query client and our internal definition of optimistic + * updates, this function constructs an object describing those same optimistic + * updates in a format we can pass into React Query's useMutation hook. In other + * words, it translates our optimistic updates definition into React Query's + * optimistic updates definition. Check their docs for details: + * https://tanstack.com/query/v4/docs/guides/optimistic-updates?from=reactQueryV3&original=https://react-query-v3.tanstack.com/guides/optimistic-updates + * + * @param queryClient The QueryClient instance used by React Query. + * @param optimisticUpdateDefinitions A list containing internal optimistic + * updates definition objects (i.e., a list where each object carries the + * instructions for performing particular optimistic update). + * @returns An object containing 'onMutate' and 'onError' functions + * corresponding to the given optimistic update definitions (check the docs + * linked above for details). + */ +function makeRqOptimisticUpdateOptions(queryClient, optimisticUpdateDefinitions) { + async function onMutate(item) { + const specificOptimisticUpdateDefinitions = optimisticUpdateDefinitions.map((generalDefinition) => getOptimisticUpdateDefinitionForSpecificItem(generalDefinition, item)); + // Cancel any outgoing refetches (so they don't overwrite our optimistic update). + // Theoretically, we can be a bit faster. Instead of awaiting the + // cancellation of all queries, we could cancel and update them in parallel. + // However, awaiting cancellation hasn't yet proven to be a performance bottleneck. + await Promise.all(specificOptimisticUpdateDefinitions.map(({ queryKey }) => queryClient.cancelQueries(queryKey))); + // We're using a Map to correctly serialize query keys that contain objects. + const previousData = new Map(); + specificOptimisticUpdateDefinitions.forEach(({ queryKey, updateQuery }) => { + // Snapshot the currently cached value. + const previousDataForQuery = queryClient.getQueryData(queryKey); + // Attempt to optimistically update the cache using the new value. + try { + queryClient.setQueryData(queryKey, updateQuery); + } + catch (e) { + console.error("The `updateQuery` function threw an exception, skipping optimistic update:"); + console.error(e); + } + // Remember the snapshotted value to restore in case of an error. + previousData.set(queryKey, previousDataForQuery); + }); + return { previousData }; + } + function onError(_err, _item, context) { + // All we do in case of an error is roll back all optimistic updates. We ensure + // not to do anything else because React Query rethrows the error. This allows + // the programmer to handle the error as they usually would (i.e., we want the + // error handling to work as it would if the programmer wasn't using optimistic + // updates). + context.previousData.forEach(async (data, queryKey) => { + await queryClient.cancelQueries(queryKey); + queryClient.setQueryData(queryKey, data); + }); + } + return { + onMutate, + onError, + }; +} +/** + * Constructs the definition for optimistically updating a specific item. It + * uses a closure over the updated item to construct an item-specific query key + * (e.g., useful when the query key depends on an ID). + * + * @param optimisticUpdateDefinition The general, "uninstantiated" optimistic + * update definition with a function for constructing the query key. + * @param item The item triggering the Action/optimistic update (i.e., the + * argument passed to the Action). + * @returns A specific optimistic update definition which corresponds to the + * provided definition and closes over the provided item. + */ +function getOptimisticUpdateDefinitionForSpecificItem(optimisticUpdateDefinition, item) { + const { getQueryKey, updateQuery } = optimisticUpdateDefinition; + return { + queryKey: getQueryKey(item), + updateQuery: (old) => updateQuery(item, old), + }; +} +/** + * Translates a Wasp query specifier to a query cache key used by React Query. + * + * @param querySpecifier A query specifier that's a part of the public API: + * https://wasp-lang.dev/docs/language/features#the-useaction-hook. + * @returns A cache key React Query internally uses for addressing queries. + */ +function getRqQueryKeyFromSpecifier(querySpecifier) { + const [queryFn, ...otherKeys] = querySpecifier; + return [...queryFn.queryCacheKey, ...otherKeys]; +} +//# sourceMappingURL=hooks.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map new file mode 100644 index 0000000000..9048c71ee2 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/hooks.js.map @@ -0,0 +1 @@ +{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../client/operations/hooks.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts index 301165fa8e..76ad094f0d 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.d.ts @@ -1,4 +1,4 @@ export * from './actions'; export * from './queries'; -export { useAction, useQuery, type OptimisticUpdateDefinition, } from './core'; +export { useAction, useQuery, type OptimisticUpdateDefinition, } from './hooks'; export { configureQueryClient, initializeQueryClient, queryClientInitialized } from './queryClient'; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js index f83307c7b1..fd2c6b29b0 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js @@ -6,7 +6,7 @@ export { // PUBLIC API useAction, // PUBLIC API -useQuery, } from './core'; +useQuery, } from './hooks'; export { // PUBLIC API configureQueryClient, diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js.map index 982c957a9a..a6cf9161ab 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,QAAQ,CAAA;AAEf,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../client/operations/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,cAAc,WAAW,CAAA;AACzB,+CAA+C;AAC/C,cAAc,WAAW,CAAA;AAEzB,OAAO;AACH,aAAa;AACb,SAAS;AACT,aAAa;AACb,QAAQ,GAGX,MAAM,SAAS,CAAA;AAEhB,OAAO;AACH,aAAa;AACb,oBAAoB;AACpB,+BAA+B;AAC/B,qBAAqB;AACrB,+BAA+B;AAC/B,sBAAsB,EACzB,MAAM,eAAe,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts index 93bbd1ddaa..c70de80ba6 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.d.ts @@ -1,12 +1,25 @@ import { Route } from 'wasp/client'; -import type { _Awaited, _ReturnType } from 'wasp/universal/types'; -import { type Query } from '../core.js'; -export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; -export declare function addMetadataToQuery(query: (...args: any[]) => Promise, metadata: { - relativeQueryPath: string; +import type { GenericBackendOperation, GenericOperationRpc, OperationRpcFor, Query, QueryMetadata } from '../rpc.js'; +export declare function makeQueryCacheKey(query: Query, payload: Input): (string | Input)[]; +export declare function createQuery(relativeQueryPath: string, entitiesUsed: string[]): QueryFor; +export declare function buildAndRegisterQuery(queryFn: QF, { queryCacheKey, queryRoute, entitiesUsed }: { + queryCacheKey: string[]; queryRoute: Route; entitiesUsed: string[]; -}): void; -export type QueryFor = Query[0], _Awaited<_ReturnType>>; -type GenericBackendQuery = (args: never, context: any) => unknown; +}): QueryForFunction; +/** + * Constructs the client Query object type from the type of the Query's definition + * on the backend. + */ +export type QueryFor = QueryForFunction>; +/** + * Constructs the client Query function type from the type of the Query's + * definition on the backend. + */ +type QueryFunctionFor = OperationRpcFor; +/** + * Returns the appropriate client Query object type for the provided client + * Query function type. + */ +type QueryForFunction = QF & QueryMetadata; export {}; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js index c03f172443..fefdfc58fc 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js @@ -1,18 +1,28 @@ import { callOperation, makeOperationRoute } from '../internal/index.js'; import { addResourcesUsedByQuery, getActiveOptimisticUpdates, } from '../internal/resources'; +// PRIVATE API (used in the SDK) +export function makeQueryCacheKey(query, payload) { + return payload !== undefined ? + [...query.queryCacheKey, payload] + : query.queryCacheKey; +} +// PRIVATE API (unsed in SDK) export function createQuery(relativeQueryPath, entitiesUsed) { const queryRoute = makeOperationRoute(relativeQueryPath); - async function query(queryKey, queryArgs) { + const queryCacheKey = [relativeQueryPath]; + const queryFn = async (queryArgs) => { const serverResult = await callOperation(queryRoute, queryArgs); - return getActiveOptimisticUpdates(queryKey).reduce((result, update) => update(result), serverResult); - } - addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }); - return query; + const queryCacheKey = makeQueryCacheKey(queryFn, queryArgs); + return getActiveOptimisticUpdates(queryCacheKey).reduce((result, update) => update(result), serverResult); + }; + return buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }); } -// PRIVATE API -export function addMetadataToQuery(query, { relativeQueryPath, queryRoute, entitiesUsed }) { - query.queryCacheKey = [relativeQueryPath]; +// PRIVATE API (used in SDK) +export function buildAndRegisterQuery(queryFn, { queryCacheKey, queryRoute, entitiesUsed }) { + const query = queryFn; + query.queryCacheKey = queryCacheKey; query.route = queryRoute; addResourcesUsedByQuery(query.queryCacheKey, entitiesUsed); + return query; } //# sourceMappingURL=core.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map index dcc40d2693..0ef0547c44 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/core.js.map @@ -1 +1 @@ -{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IAExD,KAAK,UAAU,KAAK,CAAC,QAAQ,EAAE,SAAS;QACtC,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,OAAO,0BAA0B,CAAC,QAAQ,CAAC,CAAC,MAAM,CAChD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAA;IAE1E,OAAO,KAAK,CAAA;AACd,CAAC;AAYD,cAAc;AACd,MAAM,UAAU,kBAAkB,CAChC,KAAK,EACL,EAAE,iBAAiB,EAAE,UAAU,EAAE,YAAY,EAAE;IAE/C,KAAK,CAAC,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IACzC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;AAC5D,CAAC"} \ No newline at end of file +{"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../client/operations/queries/core.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,EACL,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,uBAAuB,CAAA;AAE9B,gCAAgC;AAChC,MAAM,UAAU,iBAAiB,CAC/B,KAA2B,EAC3B,OAAc;IAEd,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC;QAC5B,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC;QAC/B,CAAC,CAAC,KAAK,CAAC,aAAa,CAAA;AAC3B,CAAC;AAED,6BAA6B;AAC7B,MAAM,UAAU,WAAW,CACzB,iBAAyB,EACzB,YAAsB;IAEtB,MAAM,UAAU,GAAG,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IACxD,MAAM,aAAa,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAEzC,MAAM,OAAO,GAAmC,KAAK,EAAE,SAAS,EAAE,EAAE;QAClE,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;QAC/D,MAAM,aAAa,GAAG,iBAAiB,CAAC,OAAiC,EAAE,SAAS,CAAC,CAAA;QACrF,OAAO,0BAA0B,CAAC,aAAa,CAAC,CAAC,MAAM,CACrD,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,EAClC,YAAY,CACb,CAAA;IACH,CAAC,CAAA;IAED,OAAO,qBAAqB,CAC1B,OAAO,EACP,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,CAC5C,CAAA;AACH,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,qBAAqB,CACnC,OAAW,EACX,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAC6B;IAEtE,MAAM,KAAK,GAAG,OAA+B,CAAA;IAE7C,KAAK,CAAC,aAAa,GAAG,aAAa,CAAA;IACnC,KAAK,CAAC,KAAK,GAAG,UAAU,CAAA;IACxB,uBAAuB,CAAC,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IAE1D,OAAO,KAAK,CAAA;AACd,CAAC"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts index 575c502be1..2d9dbafe81 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.d.ts @@ -1 +1 @@ -export { addMetadataToQuery } from './core'; +export { buildAndRegisterQuery } from './core'; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js index 1c28e8d0d3..56d2e15238 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js @@ -1,3 +1,3 @@ -// PRIVATE API -export { addMetadataToQuery } from './core'; +// PRIVATE API (used in SDK) +export { buildAndRegisterQuery } from './core'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map index 5c83611fa3..44416efcfa 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/queries/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,cAAc;AACd,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../client/operations/queries/index.ts"],"names":[],"mappings":"AAEA,4BAA4B;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAA"} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts new file mode 100644 index 0000000000..ee52ec65b4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.d.ts @@ -0,0 +1,38 @@ +import { type Route } from "wasp/client"; +import type { _Awaited, _ReturnType } from "wasp/universal/types"; +/** + * The client Query object type. It's a callable Query function with some extra + * properties (metadata). + */ +export type Query = QueryFunction & QueryMetadata; +/** + * The client Action object type (unlike a Query, it's just a normal function). + */ +export type Action = ClientOperation; +/** + * The client Query function type. + */ +export type QueryFunction = ClientOperation; +/** + * All extra properties (metadata) found on a Query object type. + */ +export type QueryMetadata = { + queryCacheKey: string[]; + route: Route; +}; +/** + * Constructs the client RPC function type from the type of the operation's + * definition on the backend. + */ +export type OperationRpcFor = Parameters extends [] ? ClientOperation>> : ClientOperation[0], _Awaited<_ReturnType>>; +/** + * A supertype of all possible backend operation definitions (i.e., Queries and + * Actions) + */ +export type GenericBackendOperation = (args: never, context: any) => unknown; +/** + * A supertype of all possible frontend RPC function types. + */ +export type GenericOperationRpc = (args: never) => Promise; +type ClientOperation = [Input] extends [never] ? (args?: unknown) => Promise : (args: Input) => Promise; +export {}; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js new file mode 100644 index 0000000000..f3a500abe4 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=rpc.js.map \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map new file mode 100644 index 0000000000..a51bf309e5 --- /dev/null +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/operations/rpc.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rpc.js","sourceRoot":"","sources":["../../../client/operations/rpc.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts index 645112861a..89fd0d7587 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/dist/client/test/vitest/helpers.d.ts @@ -1,7 +1,7 @@ import { ReactElement } from 'react'; import { type SetupServer } from 'msw/node'; import { RenderResult } from '@testing-library/react'; -import { Query } from 'wasp/client/operations/core'; +import { Query } from 'wasp/client/operations/rpc'; import { Route } from 'wasp/client'; export type MockQuery = (query: Query, resJson: MockOutput) => void; export type MockApi = (route: Route, resJson: unknown) => void; diff --git a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/package.json b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/package.json index e3a3bb5440..73e355a456 100644 --- a/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/package.json +++ b/waspc/e2e-test/test-outputs/waspMigrate-golden/waspMigrate/.wasp/out/sdk/wasp/package.json @@ -41,7 +41,7 @@ "./client/auth": "./dist/client/auth/index.js", "./client/crud": "./dist/client/crud/index.js", "./client/operations": "./dist/client/operations/index.js", - "./client/operations/core": "./dist/client/operations/core.js", + "./client/operations/rpc": "./dist/client/operations/rpc.js", "./client/router": "./dist/client/router/index.js", "./client/test": "./dist/client/test/index.js", "./client/test/*": "./dist/client/test/*.js", From 8e93092ab2a0ac6399dd149c313c1413899c1069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Tue, 7 May 2024 13:13:21 +0200 Subject: [PATCH 32/32] Add operations to todoApp --- waspc/examples/todoApp/main.wasp | 87 ++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 38 deletions(-) diff --git a/waspc/examples/todoApp/main.wasp b/waspc/examples/todoApp/main.wasp index 46cb5ce3c2..1df9847ed5 100644 --- a/waspc/examples/todoApp/main.wasp +++ b/waspc/examples/todoApp/main.wasp @@ -5,18 +5,18 @@ app todoApp { title: "ToDo App", // head: [], webSocket: { - fn: import { webSocketFn } from "@src/webSocket.js", + fn: import { webSocketFn } from "@src/webSocket", // autoConnect: false }, auth: { userEntity: User, methods: { // usernameAndPassword: { - // userSignupFields: import { userSignupFields } from "@src/auth/github.js", + // userSignupFields: import { userSignupFields } from "@src/auth/github", // }, google: { - configFn: import { config } from "@src/auth/google.js", - userSignupFields: import { userSignupFields } from "@src/auth/google.js" + configFn: import { config } from "@src/auth/google", + userSignupFields: import { userSignupFields } from "@src/auth/google" }, gitHub: { configFn: import { config } from "@src/auth/github.js", @@ -24,17 +24,17 @@ app todoApp { }, // keycloak: {}, email: { - userSignupFields: import { userSignupFields } from "@src/auth/email.js", + userSignupFields: import { userSignupFields } from "@src/auth/email", fromField: { name: "ToDO App", email: "mihovil@ilakovac.com" }, emailVerification: { - getEmailContentFn: import { getVerificationEmailContent } from "@src/auth/email.js", + getEmailContentFn: import { getVerificationEmailContent } from "@src/auth/email", clientRoute: EmailVerificationRoute, }, passwordReset: { - getEmailContentFn: import { getPasswordResetEmailContent } from "@src/auth/email.js", + getEmailContentFn: import { getPasswordResetEmailContent } from "@src/auth/email", clientRoute: PasswordResetRoute }, }, @@ -43,18 +43,18 @@ app todoApp { onAuthSucceededRedirectTo: "/profile" }, server: { - setupFn: import setup from "@src/serverSetup.js", - middlewareConfigFn: import { serverMiddlewareFn } from "@src/serverSetup.js", + setupFn: import setup from "@src/serverSetup", + middlewareConfigFn: import { serverMiddlewareFn } from "@src/serverSetup", }, client: { - rootComponent: import { App } from "@src/App.tsx", - setupFn: import setup from "@src/clientSetup.js" + rootComponent: import { App } from "@src/App", + setupFn: import setup from "@src/clientSetup" }, db: { system: PostgreSQL, seeds: [ - import { devSeedSimple } from "@src/dbSeeds.js", - import { prodSeed } from "@src/dbSeeds.js" + import { devSeedSimple } from "@src/dbSeeds", + import { prodSeed } from "@src/dbSeeds" ] }, emailSender: { @@ -82,44 +82,44 @@ psl=} route SignupRoute { path: "/signup", to: SignupPage } page SignupPage { - component: import Signup from "@src/pages/auth/Signup.tsx" + component: import Signup from "@src/pages/auth/Signup" } route LoginRoute { path: "/login", to: LoginPage } page LoginPage { - component: import Login from "@src/pages/auth/Login.tsx" + component: import Login from "@src/pages/auth/Login" } route PasswordResetRoute { path: "/password-reset", to: PasswordResetPage } page PasswordResetPage { - component: import { PasswordReset } from "@src/pages/auth/PasswordReset.tsx", + component: import { PasswordReset } from "@src/pages/auth/PasswordReset", } route EmailVerificationRoute { path: "/email-verification-", to: EmailVerificationPage } page EmailVerificationPage { - component: import { EmailVerification } from "@src/pages/auth/EmailVerification.tsx", + component: import { EmailVerification } from "@src/pages/auth/EmailVerification", } route RequestPasswordResetRoute { path: "/request-password-reset", to: RequestPasswordResetPage } page RequestPasswordResetPage { - component: import { RequestPasswordReset } from "@src/pages/auth/RequestPasswordReset.tsx", + component: import { RequestPasswordReset } from "@src/pages/auth/RequestPasswordReset", } route HomeRoute { path: "/", to: MainPage } page MainPage { authRequired: true, - component: import Main from "@src/pages/Main.jsx" + component: import Main from "@src/pages/Main" } route AboutRoute { path: "/about", to: AboutPage } page AboutPage { - component: import About from "@src/pages/About.jsx" + component: import About from "@src/pages/About" } route ProfileRoute { path: "/profile", to: ProfilePage } page ProfilePage { authRequired: true, - component: import { ProfilePage } from "@src/pages/ProfilePage.tsx" + component: import { ProfilePage } from "@src/pages/ProfilePage" } // Page for viewing a specific task @@ -127,84 +127,95 @@ page ProfilePage { route TaskRoute { path: "/task/:id", to: TaskPage } page TaskPage { authRequired: true, - component: import Task from "@src/pages/Task.tsx" + component: import Task from "@src/pages/Task" } // --------- Queries --------- // query getTasks { - fn: import { getTasks } from "@src/queries.js", + fn: import { getTasks } from "@src/queries", entities: [Task] } api fooBar { - fn: import { fooBar } from "@src/apis.js", - middlewareConfigFn: import { fooBarMiddlewareFn } from "@src/apis.js", + fn: import { fooBar } from "@src/apis", + middlewareConfigFn: import { fooBarMiddlewareFn } from "@src/apis", entities: [Task], // ALL here let's our CORS work. If we did GET, we would need an apiNamespace over it with CORS. httpRoute: (ALL, "/foo/bar") } apiNamespace bar { - middlewareConfigFn: import { barNamespaceMiddlewareFn } from "@src/apis.js", + middlewareConfigFn: import { barNamespaceMiddlewareFn } from "@src/apis", path: "/bar" } api barBaz { - fn: import { barBaz } from "@src/apis.js", + fn: import { barBaz } from "@src/apis", auth: false, entities: [Task], httpRoute: (GET, "/bar/baz") } api webhookCallback { - fn: import { webhookCallback } from "@src/apis.js", - middlewareConfigFn: import { webhookCallbackMiddlewareFn } from "@src/apis.js", + fn: import { webhookCallback } from "@src/apis", + middlewareConfigFn: import { webhookCallbackMiddlewareFn } from "@src/apis", httpRoute: (POST, "/webhook/callback"), auth: false } query getNumTasks { - fn: import { getNumTasks } from "@src/queries.js", + fn: import { getNumTasks } from "@src/queries", entities: [Task], auth: false } query getTask { - fn: import { getTask } from "@src/queries.js", + fn: import { getTask } from "@src/queries", entities: [Task] } query getDate { - fn: import { getDate } from "@src/queries.js" + fn: import { getDate } from "@src/queries" } +query getAnything { + fn: import { getAnything } from "@src/queries", + entities: [] +} + +query getTrueVoid { + fn: import { getTrueVoid } from "@src/queries", + entities: [] +} + + // --------- Actions --------- // action createTask { - fn: import { createTask } from "@src/actions.js", + fn: import { createTask } from "@src/actions", entities: [Task] } action updateTaskIsDone { - fn: import { updateTaskIsDone } from "@src/actions.js", + fn: import { updateTaskIsDone } from "@src/actions", entities: [Task] } action deleteCompletedTasks { - fn: import { deleteCompletedTasks } from "@src/actions.js", + fn: import { deleteCompletedTasks } from "@src/actions", entities: [Task] } action toggleAllTasks { - fn: import { toggleAllTasks } from "@src/actions.js", + fn: import { toggleAllTasks } from "@src/actions", entities: [Task] } job mySpecialJob { executor: PgBoss, perform: { - fn: import { foo } from "@src/jobs/bar.js", + fn: import { foo } from "@src/jobs/bar", executorOptions: { pgBoss: {=json { "retryLimit": 1 } json=} } @@ -215,7 +226,7 @@ job mySpecialJob { job mySpecialScheduledJob { executor: PgBoss, perform: { - fn: import { foo } from "@src/jobs/bar.js" + fn: import { foo } from "@src/jobs/bar" }, schedule: { cron: "0 * * * *",