From 18afeb4a4bd4b20809b5b66fe871cb322d55d333 Mon Sep 17 00:00:00 2001 From: danroberts Date: Wed, 4 Sep 2024 14:00:50 -0400 Subject: [PATCH 1/4] refactor(api-client-core): add plan function to operation types --- packages/api-client-core/src/GadgetFunctions.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/api-client-core/src/GadgetFunctions.ts b/packages/api-client-core/src/GadgetFunctions.ts index 1f9726aa4..f689c15e1 100644 --- a/packages/api-client-core/src/GadgetFunctions.ts +++ b/packages/api-client-core/src/GadgetFunctions.ts @@ -7,9 +7,13 @@ export type AsyncRecord = PromiseOrLiveIterator = PromiseOrLiveIterator | null>; export type AsyncRecordList = PromiseOrLiveIterator>; +export interface GQLBuilderResult { + query: string; + variables: Record; +} + export interface FindOneFunction { (fieldValue: string, options?: LimitToKnownKeys): AsyncRecord; - type: "findOne"; findByVariableName: string; operationName: string; @@ -19,6 +23,7 @@ export interface FindOneFunction { selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; + plan: (fieldValue: string, options?: LimitToKnownKeys) => GQLBuilderResult; } export interface MaybeFindOneFunction { @@ -33,6 +38,7 @@ export interface MaybeFindOneFunction selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; + plan: (fieldValue: string, options?: LimitToKnownKeys) => GQLBuilderResult; } export interface FindManyFunction { @@ -46,6 +52,7 @@ export interface FindManyFunction { selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; + plan: (options?: LimitToKnownKeys) => GQLBuilderResult; } export interface FindFirstFunction { @@ -59,6 +66,7 @@ export interface FindFirstFunction { selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; + plan: (options?: LimitToKnownKeys) => GQLBuilderResult; } export interface MaybeFindFirstFunction { @@ -72,6 +80,7 @@ export interface MaybeFindFirstFunction(options?: LimitToKnownKeys) => GQLBuilderResult; } export interface ActionWithIdAndVariables { @@ -122,6 +131,7 @@ export interface ActionFunctionMetadata(options?: LimitToKnownKeys) => GQLBuilderResult; /** @deprecated */ hasCreateOrUpdateEffect?: boolean; } @@ -162,6 +172,7 @@ export interface GetFunction { selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; + plan: (options?: LimitToKnownKeys) => GQLBuilderResult; } export interface GlobalActionFunction { From b9be38e90dd5339392d08eecd4439ab3e4593b7c Mon Sep 17 00:00:00 2001 From: danroberts Date: Wed, 4 Sep 2024 14:11:40 -0400 Subject: [PATCH 2/4] chore(api-client-core): expose the version used to generate the client --- packages/api-client-core/src/AnyClient.ts | 1 + packages/api-client-core/src/GadgetFunctions.ts | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/api-client-core/src/AnyClient.ts b/packages/api-client-core/src/AnyClient.ts index 62e1e6a24..fea8bc457 100644 --- a/packages/api-client-core/src/AnyClient.ts +++ b/packages/api-client-core/src/AnyClient.ts @@ -15,6 +15,7 @@ export interface AnyClient { mutate(graphQL: string, variables?: Record): Promise; transaction(callback: (transaction: GadgetTransaction) => Promise): Promise; internal: InternalModelManagerNamespace; + apiClientCoreVersion?: string; [$modelRelationships]?: { [modelName: string]: { [apiIdentifier: string]: { type: string; model: string } } }; } diff --git a/packages/api-client-core/src/GadgetFunctions.ts b/packages/api-client-core/src/GadgetFunctions.ts index f689c15e1..284222bb8 100644 --- a/packages/api-client-core/src/GadgetFunctions.ts +++ b/packages/api-client-core/src/GadgetFunctions.ts @@ -23,7 +23,7 @@ export interface FindOneFunction { selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; - plan: (fieldValue: string, options?: LimitToKnownKeys) => GQLBuilderResult; + plan?: (fieldValue: string, options?: LimitToKnownKeys) => GQLBuilderResult; } export interface MaybeFindOneFunction { @@ -38,7 +38,7 @@ export interface MaybeFindOneFunction selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; - plan: (fieldValue: string, options?: LimitToKnownKeys) => GQLBuilderResult; + plan?: (fieldValue: string, options?: LimitToKnownKeys) => GQLBuilderResult; } export interface FindManyFunction { @@ -52,7 +52,7 @@ export interface FindManyFunction { selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; - plan: (options?: LimitToKnownKeys) => GQLBuilderResult; + plan?: (options?: LimitToKnownKeys) => GQLBuilderResult; } export interface FindFirstFunction { @@ -66,7 +66,7 @@ export interface FindFirstFunction { selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; - plan: (options?: LimitToKnownKeys) => GQLBuilderResult; + plan?: (options?: LimitToKnownKeys) => GQLBuilderResult; } export interface MaybeFindFirstFunction { @@ -80,7 +80,7 @@ export interface MaybeFindFirstFunction(options?: LimitToKnownKeys) => GQLBuilderResult; + plan?: (options?: LimitToKnownKeys) => GQLBuilderResult; } export interface ActionWithIdAndVariables { @@ -131,7 +131,7 @@ export interface ActionFunctionMetadata(options?: LimitToKnownKeys) => GQLBuilderResult; + plan?: (options?: LimitToKnownKeys) => GQLBuilderResult; /** @deprecated */ hasCreateOrUpdateEffect?: boolean; } @@ -172,7 +172,7 @@ export interface GetFunction { selectionType: SelectionT; optionsType: OptionsT; schemaType: SchemaT | null; - plan: (options?: LimitToKnownKeys) => GQLBuilderResult; + plan?: (options?: LimitToKnownKeys) => GQLBuilderResult; } export interface GlobalActionFunction { From b7d3868dfa5a80c5c7e5b60a0911c4ac7d8d7a10 Mon Sep 17 00:00:00 2001 From: danroberts Date: Thu, 5 Sep 2024 10:06:50 -0400 Subject: [PATCH 3/4] consume plan from action in useFindOne --- packages/react/src/useFindOne.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/react/src/useFindOne.ts b/packages/react/src/useFindOne.ts index acd65b4d0..76af25f4f 100644 --- a/packages/react/src/useFindOne.ts +++ b/packages/react/src/useFindOne.ts @@ -44,14 +44,11 @@ export const useFindOne = < > => { const memoizedOptions = useStructuralMemo(options); const plan = useMemo(() => { - return findOneOperation( - manager.findOne.operationName, - id, - manager.findOne.defaultSelection, - manager.findOne.modelApiIdentifier, - memoizedOptions, - manager.findOne.namespace - ); + if (manager.findOne.plan) { + return manager.findOne.plan(id, memoizedOptions); + } else { + throw new Error("Incompatible client passed to useFindOne hook, please use an api client with version >= 0.17.0") + } }, [manager, id, memoizedOptions]); const [rawResult, refresh] = useGadgetQuery(useQueryArgs(plan, options)); From 111874f47f4d7d78d173e6595b3ffb13cdd50eb6 Mon Sep 17 00:00:00 2001 From: danroberts Date: Thu, 5 Sep 2024 10:28:59 -0400 Subject: [PATCH 4/4] refactor(react): consume new action plans from api client --- packages/react/src/useAction.ts | 17 +++++------------ packages/react/src/useBulkAction.ts | 16 +++++----------- packages/react/src/useFindBy.ts | 14 +++++--------- packages/react/src/useFindFirst.ts | 21 +++++++++------------ packages/react/src/useFindMany.ts | 12 +++++------- packages/react/src/useFindOne.ts | 4 ++-- packages/react/src/useMaybeFindFirst.ts | 19 ++++++++----------- packages/react/src/useMaybeFindOne.ts | 15 ++++++--------- 8 files changed, 45 insertions(+), 73 deletions(-) diff --git a/packages/react/src/useAction.ts b/packages/react/src/useAction.ts index f84c11433..5462250c4 100644 --- a/packages/react/src/useAction.ts +++ b/packages/react/src/useAction.ts @@ -1,6 +1,5 @@ import type { ActionFunction, DefaultSelection, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; import { - actionOperation, capitalizeIdentifier, disambiguateActionVariables, get, @@ -64,17 +63,11 @@ export const useAction = < const memoizedOptions = useStructuralMemo(options); const plan = useMemo(() => { - return actionOperation( - action.operationName, - action.defaultSelection, - action.modelApiIdentifier, - action.modelSelectionField, - action.variables, - memoizedOptions, - action.namespace, - action.isBulk, - action.hasReturnType - ); + if (action.plan) { + return action.plan(memoizedOptions); + } else { + throw new Error("Incompatible client passed to useAction hook, please use an api client with version >= 0.17.0") + } }, [action, memoizedOptions]); const [result, runMutation] = useGadgetMutation< diff --git a/packages/react/src/useBulkAction.ts b/packages/react/src/useBulkAction.ts index 0f5e96cff..437ef5656 100644 --- a/packages/react/src/useBulkAction.ts +++ b/packages/react/src/useBulkAction.ts @@ -59,17 +59,11 @@ export const useBulkAction = < > => { const memoizedOptions = useStructuralMemo(options); const plan = useMemo(() => { - return actionOperation( - action.operationName, - action.defaultSelection, - action.modelApiIdentifier, - action.modelSelectionField, - action.variables, - memoizedOptions, - action.namespace, - action.isBulk, - action.hasReturnType - ); + if (action.plan) { + return action.plan(memoizedOptions); + } else { + throw new Error("Incompatible client passed to useBulkAction hook, please use an api client with version >= 0.17.0") + } }, [action, memoizedOptions]); const [result, runMutation] = useGadgetMutation< diff --git a/packages/react/src/useFindBy.ts b/packages/react/src/useFindBy.ts index 2122ce8c4..d8257e6a4 100644 --- a/packages/react/src/useFindBy.ts +++ b/packages/react/src/useFindBy.ts @@ -50,15 +50,11 @@ export const useFindBy = < > => { const memoizedOptions = useStructuralMemo(options); const plan = useMemo(() => { - return findOneByFieldOperation( - finder.operationName, - finder.findByVariableName, - value, - finder.defaultSelection, - finder.modelApiIdentifier, - memoizedOptions, - finder.namespace - ); + if (finder.plan) { + return finder.plan(value, memoizedOptions) + } else { + throw new Error("Incompatible client passed to useFindBy hook, please use an api client with version >= 0.17.0") + } }, [finder, value, memoizedOptions]); const [rawResult, refresh] = useGadgetQuery(useQueryArgs(plan, options)); diff --git a/packages/react/src/useFindFirst.ts b/packages/react/src/useFindFirst.ts index cfae2d3f7..cdbc7b0cb 100644 --- a/packages/react/src/useFindFirst.ts +++ b/packages/react/src/useFindFirst.ts @@ -1,5 +1,5 @@ import type { DefaultSelection, FindFirstFunction, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; -import { findManyOperation, get, hydrateConnection, namespaceDataPath } from "@gadgetinc/api-client-core"; +import { get, hydrateConnection, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; import { useStructuralMemo } from "./useStructuralMemo.js"; @@ -41,19 +41,16 @@ export const useFindFirst = < ): ReadHookResult< GadgetRecord, DefaultSelection>> > => { - const firstOptions = { ...options, first: 1 }; - const memoizedOptions = useStructuralMemo(firstOptions); + const memoizedOptions = useStructuralMemo(options); const plan = useMemo(() => { - return findManyOperation( - manager.findFirst.operationName, - manager.findFirst.defaultSelection, - manager.findFirst.modelApiIdentifier, - memoizedOptions, - manager.findFirst.namespace - ); + if (manager.findFirst.plan) { + return manager.findFirst.plan(memoizedOptions); + } else { + throw new Error("Incompatible client passed to useFindFirst hook, please use an api client with version >= 0.17.0") + } }, [manager, memoizedOptions]); - const [rawResult, refresh] = useGadgetQuery(useQueryArgs(plan, firstOptions)); + const [rawResult, refresh] = useGadgetQuery(useQueryArgs(plan, options)); const result = useMemo(() => { const dataPath = namespaceDataPath([manager.findFirst.operationName], manager.findFirst.namespace); @@ -70,7 +67,7 @@ export const useFindFirst = < const error = ErrorWrapper.errorIfDataAbsent(rawResult, dataPath, options?.pause); return { ...rawResult, data, error }; - }, [manager.findFirst.operationName, options?.pause, rawResult]); + }, [manager.findFirst.namespace, manager.findFirst.operationName, options?.pause, rawResult]); return [result, refresh]; }; diff --git a/packages/react/src/useFindMany.ts b/packages/react/src/useFindMany.ts index e71ebddb3..56dee4005 100644 --- a/packages/react/src/useFindMany.ts +++ b/packages/react/src/useFindMany.ts @@ -43,13 +43,11 @@ export const useFindMany = < > => { const memoizedOptions = useStructuralMemo(options); const plan = useMemo(() => { - return findManyOperation( - manager.findMany.operationName, - manager.findMany.defaultSelection, - manager.findMany.modelApiIdentifier, - memoizedOptions, - manager.findMany.namespace - ); + if (manager.findMany.plan) { + return manager.findMany.plan(memoizedOptions); + } else { + throw new Error("Incompatible client passed to useFindMany hook, please use an api client with version >= 0.17.0") + } }, [manager, memoizedOptions]); const [rawResult, refresh] = useGadgetQuery(useQueryArgs(plan, options)); diff --git a/packages/react/src/useFindOne.ts b/packages/react/src/useFindOne.ts index 76af25f4f..6b9bcd406 100644 --- a/packages/react/src/useFindOne.ts +++ b/packages/react/src/useFindOne.ts @@ -1,5 +1,5 @@ import type { DefaultSelection, FindOneFunction, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; -import { findOneOperation, get, hydrateRecord, namespaceDataPath } from "@gadgetinc/api-client-core"; +import { get, hydrateRecord, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; import { useStructuralMemo } from "./useStructuralMemo.js"; @@ -63,7 +63,7 @@ export const useFindOne = < const error = ErrorWrapper.errorIfDataAbsent(rawResult, dataPath, options?.pause); return { ...rawResult, data, error }; - }, [manager.findOne.operationName, rawResult, options?.pause]); + }, [manager.findOne.operationName, manager.findOne.namespace, rawResult, options?.pause]); return [result, refresh]; }; diff --git a/packages/react/src/useMaybeFindFirst.ts b/packages/react/src/useMaybeFindFirst.ts index e2702519b..8332fb183 100644 --- a/packages/react/src/useMaybeFindFirst.ts +++ b/packages/react/src/useMaybeFindFirst.ts @@ -1,5 +1,5 @@ import type { DefaultSelection, FindFirstFunction, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; -import { findManyOperation, get, hydrateConnection, namespaceDataPath } from "@gadgetinc/api-client-core"; +import { get, hydrateConnection, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; import { useStructuralMemo } from "./useStructuralMemo.js"; @@ -41,19 +41,16 @@ export const useMaybeFindFirst = < ): ReadHookResult, DefaultSelection> >> => { - const firstOptions = { ...options, first: 1 }; - const memoizedOptions = useStructuralMemo(firstOptions); + const memoizedOptions = useStructuralMemo(options); const plan = useMemo(() => { - return findManyOperation( - manager.findFirst.operationName, - manager.findFirst.defaultSelection, - manager.findFirst.modelApiIdentifier, - memoizedOptions, - manager.findFirst.namespace - ); + if (manager.findFirst.plan) { + return manager.findFirst.plan(memoizedOptions); + } else { + throw new Error("Incompatible client passed to useMaybeFindFirst hook, please use an api client with version >= 0.17.0") + } }, [manager, memoizedOptions]); - const [rawResult, refresh] = useGadgetQuery(useQueryArgs(plan, firstOptions)); + const [rawResult, refresh] = useGadgetQuery(useQueryArgs(plan, memoizedOptions)); const result = useMemo(() => { const dataPath = namespaceDataPath([manager.findFirst.operationName], manager.findFirst.namespace); diff --git a/packages/react/src/useMaybeFindOne.ts b/packages/react/src/useMaybeFindOne.ts index cf9477db8..9b65dcdb7 100644 --- a/packages/react/src/useMaybeFindOne.ts +++ b/packages/react/src/useMaybeFindOne.ts @@ -1,5 +1,5 @@ import type { DefaultSelection, FindOneFunction, GadgetRecord, LimitToKnownKeys, Select } from "@gadgetinc/api-client-core"; -import { findOneOperation, get, hydrateRecord, namespaceDataPath } from "@gadgetinc/api-client-core"; +import { get, hydrateRecord, namespaceDataPath } from "@gadgetinc/api-client-core"; import { useMemo } from "react"; import { useGadgetQuery } from "./useGadgetQuery.js"; import { useStructuralMemo } from "./useStructuralMemo.js"; @@ -44,14 +44,11 @@ export const useMaybeFindOne = < >> => { const memoizedOptions = useStructuralMemo(options); const plan = useMemo(() => { - return findOneOperation( - manager.findOne.operationName, - id, - manager.findOne.defaultSelection, - manager.findOne.modelApiIdentifier, - memoizedOptions, - manager.findOne.namespace - ); + if (manager.findOne.plan) { + return manager.findOne.plan(id, memoizedOptions); + } else { + throw new Error("Incompatible client passed to useMaybeFindOne hook, please use an api client with version >= 0.17.0") + } }, [manager, id, memoizedOptions]); const [rawResult, refresh] = useGadgetQuery(useQueryArgs(plan, options));