From d204995af273ce00fc70dfe959aa7e9f6ea43746 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Sat, 15 Feb 2020 17:26:43 +0800 Subject: [PATCH 01/13] migrate to apollo 3 --- src/ApolloClient.re | 130 +++++++++++++++++++++++++ src/ApolloHooks.re | 7 +- src/ApolloHooksClient.re | 56 +++++++++++ src/ApolloHooksMutation.re | 33 ++++--- src/ApolloHooksProvider.re | 4 +- src/ApolloHooksQuery.re | 170 +++++++++++++++++++++++++++++---- src/ApolloHooksSubscription.re | 19 ++-- src/ApolloHooksTypes.re | 9 +- src/ReasonApolloTypes.re | 49 ++++++++++ 9 files changed, 427 insertions(+), 50 deletions(-) create mode 100644 src/ApolloClient.re create mode 100644 src/ApolloHooksClient.re create mode 100644 src/ReasonApolloTypes.re diff --git a/src/ApolloClient.re b/src/ApolloClient.re new file mode 100644 index 0000000..b9c6344 --- /dev/null +++ b/src/ApolloClient.re @@ -0,0 +1,130 @@ +open ReasonApolloTypes; + +type queryObj = { + query: ReasonApolloTypes.queryString, + variables: Js.Json.t, +}; + +type mutationObj = { + mutation: ReasonApolloTypes.queryString, + variables: Js.Json.t, +}; + +type updateQueryOptions = { + fetchMoreResult: option(Js.Json.t), + variables: option(Js.Json.t), +}; + +type onErrorT; +type updateQueryT = (Js.Json.t, updateQueryOptions) => Js.Json.t; +type updateSubscriptionOptions = { + subscriptionData: option(Js.Json.t), + variables: option(Js.Json.t), +}; +type updateQuerySubscriptionT = + (Js.Json.t, updateSubscriptionOptions) => Js.Json.t; + +type subscribeToMoreOptions = { + document: queryString, + variables: option(Js.Json.t), + updateQuery: option(updateQuerySubscriptionT), + onError: option(onErrorT), +}; + +type fetchMoreOptions = { + variables: option(Js.Json.t), + updateQuery: updateQueryT, +}; + +type queryResult = { + loading: bool, + data: Js.Nullable.t(Js.Json.t), + error: Js.Nullable.t(apolloError), + refetch: Js.Null_undefined.t(Js.Json.t) => Js.Promise.t(queryResult), + networkStatus: Js.Nullable.t(int), + variables: Js.Null_undefined.t(Js.Json.t), + fetchMore: fetchMoreOptions => Js.Promise.t(unit), + subscribeToMore: subscribeToMoreOptions => unit, +}; + +type mutationResult = { + loading: bool, + called: bool, + data: Js.Nullable.t(Js.Json.t), + error: Js.Nullable.t(apolloError), + networkStatus: Js.Nullable.t(int), + variables: Js.Null_undefined.t(Js.Json.t), +}; + + +type generatedApolloClient = { + query: + [@bs.meth] (queryObj => Js.Promise.t(queryResult)), + mutate: + [@bs.meth] ( + mutationObj => Js.Promise.t(mutationResult) + ), + resetStore: [@bs.meth] (unit => Js.Promise.t(unit)), +}; + +type apolloClientObjectParam = { + link: apolloLink, + cache: apolloCache, + ssrMode: option(bool), + ssrForceFetchDelay: option(int), + connectToDevTools: option(bool), + queryDeduplication: option(bool), +}; + +[@bs.module "@apollo/client"] [@bs.new] +external createApolloClientJS: apolloClientObjectParam => generatedApolloClient = + "ApolloClient"; + +[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; + +module ReadQuery = (Config: ReasonApolloTypes.Config) => { + type readQueryOptions = { + query: ReasonApolloTypes.queryString, + variables: Js.Nullable.t(Js.Json.t), + }; + type response = option(Config.t); + [@bs.send] + external readQuery: + (generatedApolloClient, readQueryOptions) => Js.Nullable.t(Js.Json.t) = + "readQuery"; + + let graphqlQueryAST = gql(. Config.query); + let apolloDataToRecord: Js.Nullable.t(Js.Json.t) => response = + apolloData => + Js.Nullable.toOption(apolloData)->(Belt.Option.map(Config.parse)); + + let make = (~client, ~variables: option(Js.Json.t)=?, ()) => + readQuery( + client, + {query: graphqlQueryAST, variables: Js.Nullable.fromOption(variables)}, + ) + ->apolloDataToRecord; +}; + +module WriteQuery = (Config: ReasonApolloTypes.Config) => { + type writeQueryOptions = { + query: ReasonApolloTypes.queryString, + variables: Js.Nullable.t(Js.Json.t), + data: Config.t, + }; + [@bs.send] + external writeQuery: (generatedApolloClient, writeQueryOptions) => unit = + "writeQuery"; + + let graphqlQueryAST = gql(. Config.query); + + let make = (~client, ~variables: option(Js.Json.t)=?, ~data: Config.t, ()) => + writeQuery( + client, + { + query: graphqlQueryAST, + variables: Js.Nullable.fromOption(variables), + data, + }, + ); +}; diff --git a/src/ApolloHooks.re b/src/ApolloHooks.re index 1143dbb..f98789f 100644 --- a/src/ApolloHooks.re +++ b/src/ApolloHooks.re @@ -4,15 +4,18 @@ module Provider = ApolloHooksProvider; module Subscription = ApolloHooksSubscription; let useQuery = Query.useQuery; +let useLazyQuery = Query.useLazyQuery; let useMutation = Mutation.useMutation; let useSubscription = Subscription.useSubscription; let toQueryObj = (result): ApolloClient.queryObj => { - "query": ApolloClient.gql(. result##query), - "variables": result##variables, + query: ApolloClient.gql(. result##query), + variables: result##variables, }; let toReadQueryOptions = result => { "query": ApolloClient.gql(. result##query), "variables": Js.Nullable.fromOption(Some(result##variables)), }; + +external toOptimisticResult: 'a => Mutation.optimisticResult = "%identity"; diff --git a/src/ApolloHooksClient.re b/src/ApolloHooksClient.re new file mode 100644 index 0000000..4b5c52a --- /dev/null +++ b/src/ApolloHooksClient.re @@ -0,0 +1,56 @@ +open ApolloHooksTypes; + +type queryError = {. "message": string}; +type queryResult('a) = { + data: option('a), + errors: option(array(queryError)), + loading: bool, + networkStatus: ApolloHooksTypes.networkStatus, + stale: bool, +}; + +[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; + +type options('data); +[@bs.obj] +external doMakeOptions: + ( + ~query: ReasonApolloTypes.queryString, + ~variables: Js.Json.t=?, + ~notifyOnNetworkStatusChange: bool=?, + ~fetchPolicy: string=?, + ~errorPolicy: string=?, + ~pollInterval: int=?, + unit + ) => + options('data) = + ""; + +let makeOptions = + ( + ~variables=?, + ~notifyOnNetworkStatusChange=?, + ~fetchPolicy=?, + ~errorPolicy=?, + ~pollInterval=?, + (_, query, _): graphqlDefinition('data, _, _), + ) => { + doMakeOptions( + ~query=gql(. query), + ~variables?, + ~notifyOnNetworkStatusChange?, + ~fetchPolicy=?fetchPolicy->Belt.Option.map(f => fetchPolicyToJs(f)), + ~errorPolicy=?errorPolicy->Belt.Option.map(e => errorPolicyToJs(e)), + ~pollInterval?, + (), + ); +}; + +[@bs.send] +external query: + (ApolloClient.generatedApolloClient, options('data)) => + Js.Promise.t(queryResult('data)) = + "query"; + +[@bs.module "../../../apolloClient"] +external client: ApolloClient.generatedApolloClient = "default"; diff --git a/src/ApolloHooksMutation.re b/src/ApolloHooksMutation.re index 7d6605b..9f91b8f 100644 --- a/src/ApolloHooksMutation.re +++ b/src/ApolloHooksMutation.re @@ -23,6 +23,8 @@ type controlledResult('a) = { error: option(error), }; +type optimisticResult; + type controlledVariantResult('a) = | Loading | Called @@ -48,6 +50,8 @@ type options('a) = { awaitRefetchQueries: bool, [@bs.optional] update: (ApolloClient.generatedApolloClient, mutationResult('a)) => unit, + [@bs.optional] + optimisticResponse: optimisticResult, }; type jsResult = { @@ -65,11 +69,12 @@ type mutation('a) = ~client: ApolloClient.generatedApolloClient=?, ~refetchQueries: refetchQueries=?, ~awaitRefetchQueries: bool=?, + ~optimisticResponse: optimisticResult=?, unit ) => Js.Promise.t(controlledVariantResult('a)); -[@bs.module "@apollo/react-hooks"] +[@bs.module "@apollo/client"] external useMutationJs: (. ReasonApolloTypes.queryString, options('a)) => (jsMutate('a), jsResult) = "useMutation"; @@ -83,29 +88,35 @@ let useMutation: ~variables: Js.Json.t=?, ~refetchQueries: refetchQueries=?, ~awaitRefetchQueries: bool=?, - ~update: (ApolloClient.generatedApolloClient, mutationResult('a)) => - unit + ~update: (ApolloClient.generatedApolloClient, mutationResult(t)) => unit =?, - (module ApolloHooksTypes.Config with type t = t) + ~optimisticResponse: optimisticResult=?, + ApolloHooksTypes.graphqlDefinition('data, _, _) ) => - (mutation(t), controlledVariantResult(t), controlledResult(t)) = + ( + mutation('data), + controlledVariantResult('data), + controlledResult('data), + ) = ( ~client=?, ~variables=?, ~refetchQueries=?, ~awaitRefetchQueries=?, ~update=?, - (module Config), + ~optimisticResponse=?, + (parse, query, _), ) => { let (jsMutate, jsResult) = useMutationJs(. - gql(. Config.query), + gql(. query), options( ~client?, ~variables?, ~refetchQueries?, ~awaitRefetchQueries?, ~update?, + ~optimisticResponse?, (), ), ); @@ -118,6 +129,7 @@ let useMutation: ~client=?, ~refetchQueries=?, ~awaitRefetchQueries=?, + ~optimisticResponse=?, (), ) => jsMutate(. @@ -126,6 +138,7 @@ let useMutation: ~client?, ~refetchQueries?, ~awaitRefetchQueries?, + ~optimisticResponse?, (), ), ) @@ -135,7 +148,7 @@ let useMutation: Js.Nullable.toOption(jsResult##data), Js.Nullable.toOption(jsResult##error), ) { - | (Some(data), _) => Data(Config.parse(data)) + | (Some(data), _) => Data(parse(data)) | (None, Some(error)) => Error(error) | (None, None) => NoData } @@ -152,9 +165,7 @@ let useMutation: loading: jsResult##loading, called: jsResult##called, data: - jsResult##data - ->Js.Nullable.toOption - ->Belt.Option.map(Config.parse), + jsResult##data->Js.Nullable.toOption->Belt.Option.map(parse), error: jsResult##error->Js.Nullable.toOption, }, [|jsResult|], diff --git a/src/ApolloHooksProvider.re b/src/ApolloHooksProvider.re index 7ad79c1..6a050c1 100644 --- a/src/ApolloHooksProvider.re +++ b/src/ApolloHooksProvider.re @@ -1,5 +1,5 @@ -[@bs.module "@apollo/react-hooks"] [@react.component] +[@bs.module "@apollo/client"] [@react.component] external make: (~client: ApolloClient.generatedApolloClient, ~children: React.element) => React.element = - "ApolloProvider"; \ No newline at end of file + "ApolloProvider"; diff --git a/src/ApolloHooksQuery.re b/src/ApolloHooksQuery.re index 8943510..b9ff8d5 100644 --- a/src/ApolloHooksQuery.re +++ b/src/ApolloHooksQuery.re @@ -12,14 +12,14 @@ type variant('a) = * apollo-client/src/core/ObservableQuery.ts */ [@bs.deriving abstract] -type updateQueryOptions = { +type updateQueryOptions('a) = { [@bs.optional] - fetchMoreResult: Js.Json.t, + fetchMoreResult: option('a), [@bs.optional] variables: Js.Json.t, }; -type updateQueryT = (Js.Json.t, updateQueryOptions) => Js.Json.t; +type updateQueryT('a) = ('a, updateQueryOptions('a)) => 'a; type refetch('a) = (~variables: Js.Json.t=?, unit) => Js.Promise.t('a); type queryResult('a) = { @@ -28,7 +28,7 @@ type queryResult('a) = { error: option(queryError), refetch: refetch('a), fetchMore: - (~variables: Js.Json.t=?, ~updateQuery: updateQueryT, unit) => + (~variables: Js.Json.t=?, ~updateQuery: updateQueryT('a), unit) => Js.Promise.t(unit), networkStatus: ApolloHooksTypes.networkStatus, }; @@ -37,10 +37,10 @@ type queryResult('a) = { * apollo-client/src/core/watchQueryOptions.ts */ [@bs.deriving abstract] -type fetchMoreOptions = { +type fetchMoreOptions('a) = { [@bs.optional] variables: Js.Json.t, - updateQuery: updateQueryT, + updateQuery: updateQueryT('a), }; [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; @@ -63,7 +63,7 @@ type options = { pollInterval: int, }; -[@bs.module "@apollo/react-hooks"] +[@bs.module "@apollo/client"] external useQueryJs: (ReasonApolloTypes.queryString, options) => { @@ -73,24 +73,23 @@ external useQueryJs: "error": Js.Nullable.t(queryError), [@bs.meth] "refetch": Js.Nullable.t(Js.Json.t) => Js.Promise.t(Js.Json.t), - [@bs.meth] "fetchMore": fetchMoreOptions => Js.Promise.t(unit), + [@bs.meth] "fetchMore": fetchMoreOptions('a) => Js.Promise.t(unit), "networkStatus": Js.Nullable.t(int), } = "useQuery"; let useQuery: - type t. - ( - ~client: ApolloClient.generatedApolloClient=?, - ~variables: Js.Json.t=?, - ~notifyOnNetworkStatusChange: bool=?, - ~fetchPolicy: ApolloHooksTypes.fetchPolicy=?, - ~errorPolicy: ApolloHooksTypes.errorPolicy=?, - ~skip: bool=?, - ~pollInterval: int=?, - (module Config with type t = t) - ) => - (variant(t), queryResult(t)) = + ( + ~client: ApolloClient.generatedApolloClient=?, + ~variables: Js.Json.t=?, + ~notifyOnNetworkStatusChange: bool=?, + ~fetchPolicy: ApolloHooksTypes.fetchPolicy=?, + ~errorPolicy: ApolloHooksTypes.errorPolicy=?, + ~skip: bool=?, + ~pollInterval: int=?, + graphqlDefinition('data, _, _) + ) => + (variant('data), queryResult('data)) = ( ~client=?, ~variables=?, @@ -99,7 +98,7 @@ let useQuery: ~errorPolicy=?, ~skip=?, ~pollInterval=?, - (module Config), + (parse, query, _), ) => { let jsResult = useQueryJs( @@ -118,6 +117,133 @@ let useQuery: ), ); + let getData = obj => + obj + ->Js.Json.decodeObject + ->Belt.Option.flatMap(x => Js.Dict.get(x, "data")) + ->Belt.Option.getExn; + + let data = + React.useMemo1( + () => + jsResult##data + ->Js.Nullable.toOption + ->Belt.Option.flatMap(data => + switch (parse(data)) { + | parsedData => Some(parsedData) + | exception _ => None + } + ), + [|jsResult|], + ); + + let result = { + data, + loading: jsResult##loading, + error: jsResult##error->Js.Nullable.toOption, + networkStatus: + ApolloHooksTypes.toNetworkStatus(jsResult##networkStatus), + refetch: (~variables=?, ()) => + jsResult##refetch(Js.Nullable.fromOption(variables)) + |> Js.Promise.then_(result => + parse(result->getData) |> Js.Promise.resolve + ), + fetchMore: (~variables=?, ~updateQuery, ()) => + jsResult##fetchMore(fetchMoreOptions(~variables?, ~updateQuery, ())), + }; + + let simple = + React.useMemo1( + () => + switch (result) { + | {loading: true} => Loading + | {error: Some(error)} => Error(error) + | {data: Some(data)} => Data(data) + | _ => NoData + }, + [|result|], + ); + + (simple, result); + }; + +type lazyVariant('a) = + | Data('a) + | Error(queryError) + | Loading + | NoData + | NotCalled; + +type lazyQueryResult('a) = { + called: bool, + data: option('a), + loading: bool, + error: option(queryError), + refetch: refetch('a), + fetchMore: + (~variables: Js.Json.t=?, ~updateQuery: updateQueryT('a), unit) => + Js.Promise.t(unit), + networkStatus: ApolloHooksTypes.networkStatus, +}; + +[@bs.module "@apollo/client"] +external useLazyQueryJs: + (ReasonApolloTypes.queryString, options) => + ( + unit => unit, + { + . + "data": Js.Nullable.t(Js.Json.t), + "loading": bool, + "error": Js.Nullable.t(queryError), + [@bs.meth] + "refetch": Js.Nullable.t(Js.Json.t) => Js.Promise.t(Js.Json.t), + [@bs.meth] "fetchMore": fetchMoreOptions('a) => Js.Promise.t(unit), + "networkStatus": Js.Nullable.t(int), + "called": bool, + }, + ) = + "useLazyQuery"; + +let useLazyQuery: + ( + ~client: ApolloClient.generatedApolloClient=?, + ~variables: Js.Json.t=?, + ~notifyOnNetworkStatusChange: bool=?, + ~fetchPolicy: ApolloHooksTypes.fetchPolicy=?, + ~errorPolicy: ApolloHooksTypes.errorPolicy=?, + ~skip: bool=?, + ~pollInterval: int=?, + graphqlDefinition('data, _, _) + ) => + (unit => unit, lazyVariant('data), lazyQueryResult('data)) = + ( + ~client=?, + ~variables=?, + ~notifyOnNetworkStatusChange=?, + ~fetchPolicy=?, + ~errorPolicy=?, + ~skip=?, + ~pollInterval=?, + (parse, query, _), + ) => { + let (load, jsResult) = + useLazyQueryJs( + gql(. query), + options( + ~variables?, + ~client?, + ~notifyOnNetworkStatusChange?, + ~fetchPolicy=? + fetchPolicy->Belt.Option.map(ApolloHooksTypes.fetchPolicyToJs), + ~errorPolicy=? + errorPolicy->Belt.Option.map(ApolloHooksTypes.errorPolicyToJs), + ~skip?, + ~pollInterval?, + (), + ), + ); + let parse = Config.parse; let getData = obj => obj @@ -151,6 +277,7 @@ let useQuery: jsResult##fetchMore( fetchMoreOptions(~variables?, ~updateQuery, ()), ), + called: jsResult##called, }, [|jsResult|], ); @@ -162,6 +289,7 @@ let useQuery: | {loading: true} => Loading | {error: Some(error)} => Error(error) | {data: Some(data)} => Data(data) + | {called: false} => NotCalled | _ => NoData }, [|result|], diff --git a/src/ApolloHooksSubscription.re b/src/ApolloHooksSubscription.re index 6eca7f5..1f263db 100644 --- a/src/ApolloHooksSubscription.re +++ b/src/ApolloHooksSubscription.re @@ -1,3 +1,4 @@ +open ApolloHooksTypes; type error = {. "message": string}; type variant('a) = @@ -26,8 +27,8 @@ type options = { client: ApolloClient.generatedApolloClient, }; -[@bs.module "@apollo/react-hooks"] -external useSubscriptionJs: +[@bs.module "@apollo/client"] +external useSubscription: (ReasonApolloTypes.queryString, options) => { . @@ -38,23 +39,23 @@ external useSubscriptionJs: "useSubscription"; let useSubscription: - type t. + ( ~variables: Js.Json.t=?, ~client: ApolloClient.generatedApolloClient=?, - (module ApolloHooksTypes.Config with type t = t) + graphqlDefinition('data, _, _) ) => - (variant(t), result(t)) = - (~variables=?, ~client=?, (module Config)) => { + (variant('data), result('data)) = + (~variables=?, ~client=?, (parse, query, _)) => { let jsResult = - useSubscriptionJs( - gql(. Config.query), + useSubscription( + gql(. query), options(~variables?, ~client?, ()), ); let result = { data: - jsResult##data->Js.Nullable.toOption->Belt.Option.map(Config.parse), + jsResult##data->Js.Nullable.toOption->Belt.Option.map(parse), loading: jsResult##loading, error: jsResult##error->Js.Nullable.toOption, }; diff --git a/src/ApolloHooksTypes.re b/src/ApolloHooksTypes.re index 9c5f47d..9ab6985 100644 --- a/src/ApolloHooksTypes.re +++ b/src/ApolloHooksTypes.re @@ -61,8 +61,7 @@ let errorPolicyToJs = errorPolicy => | All => "all" }; -module type Config = { - type t; - let query: string; - let parse: Js.Json.t => t; -}; +type parse('a) = Js.Json.t => 'a; +type query = string; + +type graphqlDefinition('data, 'b, 'c) = (parse('data), query, 'b); diff --git a/src/ReasonApolloTypes.re b/src/ReasonApolloTypes.re new file mode 100644 index 0000000..2109874 --- /dev/null +++ b/src/ReasonApolloTypes.re @@ -0,0 +1,49 @@ +/** + * An abstract type to describe a query string object. + */ +type queryString; + +/** + * The signature of the `graphql-tag/gql` function that transforms a GraphQL + * query string to the standard GraphQL AST. + * https://github.com/apollographql/graphql-tag + */ +type gql = (. string) => queryString; + +/** + * An abstract type to describe an Apollo Link object. + */ +type apolloLink; + +/** + * An abstract type to describe an Apollo Cache object. + */ +type apolloCache; + +type apolloErrorExtensions = {code: Js.Nullable.t(string)}; + +type graphqlError = { + message: string, + name: Js.Nullable.t(string), + extensions: Js.Nullable.t(apolloErrorExtensions), + locations: Js.Nullable.t(array(string)), + path: Js.Nullable.t(array(string)), + nodes: Js.Nullable.t(array(string)), +}; + +type executionResult = { + errors: Js.Nullable.t(Js.Array.t(graphqlError)), + data: Js.Nullable.t(Js.Json.t), +}; + +module type Config = { + let query: string; + type t; + let parse: Js.Json.t => t; +}; + +type apolloError = { + message: string, + graphQLErrors: Js.Nullable.t(array(graphqlError)), + networkError: Js.Nullable.t(string), +}; From be25c3babdb59e520d895e150ad2bae17ada70ac Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Sat, 15 Feb 2020 17:29:49 +0800 Subject: [PATCH 02/13] remove dependency on reason-apollo --- bsconfig.json | 2 +- package.json | 1 - yarn.lock | 257 +------------------------------------------------- 3 files changed, 6 insertions(+), 254 deletions(-) diff --git a/bsconfig.json b/bsconfig.json index 6f45cb3..9b60530 100644 --- a/bsconfig.json +++ b/bsconfig.json @@ -20,6 +20,6 @@ } ], "suffix": ".bs.js", - "bs-dependencies": ["reason-react", "reason-apollo"], + "bs-dependencies": ["reason-react"], "refmt": 3 } diff --git a/package.json b/package.json index 1ebfdd9..6cac9a5 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ "bs-platform": "^5.0.6", "husky": "^3.0.5", "lint-staged": "^9.4.0", - "reason-apollo": "^0.17.0", "reason-react": ">=0.7.0" }, "peerDependencies": { diff --git a/yarn.lock b/yarn.lock index 05d122c..9d11eb7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -227,11 +227,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.8.tgz#cb1bf6800238898bc2ff6ffa5702c3cadd350708" integrity sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A== -"@types/node@>=6": - version "12.7.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.2.tgz#c4e63af5e8823ce9cc3f0b34f7b998c2171f0c44" - integrity sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg== - "@types/node@^12.0.2": version "12.7.11" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446" @@ -247,20 +242,7 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.0.2.tgz#5e8b09f0e4af53034b1d0fb9977a277847836205" integrity sha512-G1Ggy7/9Nsa1Jt2yiBR2riEuyK2DFNnqow6R7cromXPMNynackRY1vqFTLz/gwnef1LHokbXThcPhqMRjUbkpQ== -"@types/zen-observable@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.0.tgz#8b63ab7f1aa5321248aad5ac890a485656dcea4d" - integrity sha512-te5lMAWii1uEJ4FwLjzdlbw3+n0FZNOvFXHxQDKeT0dilh7HOzdMzV2TrJVUzq8ep7J4Na8OUYPRLSQkJHAlrg== - -"@wry/context@^0.4.0": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.4.4.tgz#e50f5fa1d6cfaabf2977d1fda5ae91717f8815f8" - integrity sha512-LrKVLove/zw6h2Md/KZyWxIkFM6AoyKp71OqpH9Hiip1csjPVoD3tPxlbQUNxEnHENks3UGgNpSBCAfq9KWuag== - dependencies: - "@types/node" ">=6" - tslib "^1.9.3" - -"@wry/equality@^0.1.2", "@wry/equality@^0.1.9": +"@wry/equality@^0.1.9": version "0.1.9" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.9.tgz#b13e18b7a8053c6858aa6c85b54911fb31e3a909" integrity sha512-mB6ceGjpMGz1ZTza8HYnrPGos2mC6So4NhS1PtZ8s4Qt0K7fBiIGhpSxUbQmhwcSWE3no+bYxmI2OL6KuXYmoQ== @@ -315,111 +297,6 @@ any-observable@^0.3.0: resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== -apollo-cache-inmemory@^1.6.0: - version "1.6.3" - resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.6.3.tgz#826861d20baca4abc45f7ca7a874105905b8525d" - integrity sha512-S4B/zQNSuYc0M/1Wq8dJDTIO9yRgU0ZwDGnmlqxGGmFombOZb9mLjylewSfQKmjNpciZ7iUIBbJ0mHlPJTzdXg== - dependencies: - apollo-cache "^1.3.2" - apollo-utilities "^1.3.2" - optimism "^0.10.0" - ts-invariant "^0.4.0" - tslib "^1.9.3" - -apollo-cache@1.3.2, apollo-cache@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.3.2.tgz#df4dce56240d6c95c613510d7e409f7214e6d26a" - integrity sha512-+KA685AV5ETEJfjZuviRTEImGA11uNBp/MJGnaCvkgr+BYRrGLruVKBv6WvyFod27WEB2sp7SsG8cNBKANhGLg== - dependencies: - apollo-utilities "^1.3.2" - tslib "^1.9.3" - -apollo-client@^2.6.3: - version "2.6.4" - resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-2.6.4.tgz#872c32927263a0d34655c5ef8a8949fbb20b6140" - integrity sha512-oWOwEOxQ9neHHVZrQhHDbI6bIibp9SHgxaLRVPoGvOFy7OH5XUykZE7hBQAVxq99tQjBzgytaZffQkeWo1B4VQ== - dependencies: - "@types/zen-observable" "^0.8.0" - apollo-cache "1.3.2" - apollo-link "^1.0.0" - apollo-utilities "1.3.2" - symbol-observable "^1.0.2" - ts-invariant "^0.4.0" - tslib "^1.9.3" - zen-observable "^0.8.0" - -apollo-link-context@^1.0.18: - version "1.0.18" - resolved "https://registry.yarnpkg.com/apollo-link-context/-/apollo-link-context-1.0.18.tgz#9e700e3314da8ded50057fee0a18af2bfcedbfc3" - integrity sha512-aG5cbUp1zqOHHQjAJXG7n/izeMQ6LApd/whEF5z6qZp5ATvcyfSNkCfy3KRJMMZZ3iNfVTs6jF+IUA8Zvf+zeg== - dependencies: - apollo-link "^1.2.12" - tslib "^1.9.3" - -apollo-link-error@^1.1.11: - version "1.1.11" - resolved "https://registry.yarnpkg.com/apollo-link-error/-/apollo-link-error-1.1.11.tgz#7cd363179616fb90da7866cee85cb00ee45d2f3b" - integrity sha512-442DNqn3CNRikDaenMMkoDmCRmkoUx/XyUMlRTZBEFdTw3FYPQLsmDO3hzzC4doY5/BHcn9/jdYh9EeLx4HPsA== - dependencies: - apollo-link "^1.2.12" - apollo-link-http-common "^0.2.14" - tslib "^1.9.3" - -apollo-link-http-common@^0.2.14, apollo-link-http-common@^0.2.5: - version "0.2.14" - resolved "https://registry.yarnpkg.com/apollo-link-http-common/-/apollo-link-http-common-0.2.14.tgz#d3a195c12e00f4e311c417f121181dcc31f7d0c8" - integrity sha512-v6mRU1oN6XuX8beVIRB6OpF4q1ULhSnmy7ScnHnuo1qV6GaFmDcbdvXqxIkAV1Q8SQCo2lsv4HeqJOWhFfApOg== - dependencies: - apollo-link "^1.2.12" - ts-invariant "^0.4.0" - tslib "^1.9.3" - -apollo-link-http@^1.5.15: - version "1.5.15" - resolved "https://registry.yarnpkg.com/apollo-link-http/-/apollo-link-http-1.5.15.tgz#106ab23bb8997bd55965d05855736d33119652cf" - integrity sha512-epZFhCKDjD7+oNTVK3P39pqWGn4LEhShAoA1Q9e2tDrBjItNfviiE33RmcLcCURDYyW5JA6SMgdODNI4Is8tvQ== - dependencies: - apollo-link "^1.2.12" - apollo-link-http-common "^0.2.14" - tslib "^1.9.3" - -apollo-link-ws@^1.0.18: - version "1.0.18" - resolved "https://registry.yarnpkg.com/apollo-link-ws/-/apollo-link-ws-1.0.18.tgz#281b9b0826d5fc7e2aa14d2784c5193d8b761112" - integrity sha512-nrWh9m7k1FQw1AK1GB1VTJS0o01cpsP2RYmTAh2j+P4lL2/72WgsblhbuF+yA1/jsgVrzg6xa+TNw3UwgGp3+g== - dependencies: - apollo-link "^1.2.12" - tslib "^1.9.3" - -apollo-link@^1.0.0, apollo-link@^1.2.12, apollo-link@^1.2.3: - version "1.2.12" - resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.12.tgz#014b514fba95f1945c38ad4c216f31bcfee68429" - integrity sha512-fsgIAXPKThyMVEMWQsUN22AoQI+J/pVXcjRGAShtk97h7D8O+SPskFinCGEkxPeQpE83uKaqafB2IyWdjN+J3Q== - dependencies: - apollo-utilities "^1.3.0" - ts-invariant "^0.4.0" - tslib "^1.9.3" - zen-observable-ts "^0.8.19" - -apollo-upload-client@9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/apollo-upload-client/-/apollo-upload-client-9.1.0.tgz#13191714ae07388088f2c773ebbfd53ba2f64c53" - integrity sha512-ZN5gsbBjImEZTWWTUHpCEGDasnoBGbaODpznQ5EawyNHceuFYSNJbbft+ZZ841vZAcj9XZdKUKoaLBlMZ/r7nw== - dependencies: - apollo-link "^1.2.3" - apollo-link-http-common "^0.2.5" - extract-files "^4.0.0" - -apollo-utilities@1.3.2, apollo-utilities@^1.3.0, apollo-utilities@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.3.2.tgz#8cbdcf8b012f664cd6cb5767f6130f5aed9115c9" - integrity sha512-JWNHj8XChz7S4OZghV6yc9FNnzEXj285QYp/nLNh943iObycI5GTDO3NGR9Dth12LRrSFMeDOConPfPln+WGfg== - dependencies: - "@wry/equality" "^0.1.2" - fast-json-stable-stringify "^2.0.0" - ts-invariant "^0.4.0" - tslib "^1.9.3" - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -447,11 +324,6 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - babel-polyfill@6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" @@ -469,11 +341,6 @@ babel-runtime@^6.23.0, babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" -backo2@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" - integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= - balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -775,11 +642,6 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -eventemitter3@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== - execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -808,11 +670,6 @@ execa@^2.0.3: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -extract-files@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-4.1.0.tgz#2d5b64af688dfd030274ca542c43fabba325019a" - integrity sha512-2gjdb3dVzr1ie9+K8pupPTnsNkK4qmzbTFOIxghiWoh6nCTajGCGC72ZNYX0nBWy5IOq1FXfRVgvkkLqqE4sdw== - fast-glob@^3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.0.4.tgz#d484a41005cb6faeb399b951fd1bd70ddaebb602" @@ -825,11 +682,6 @@ fast-glob@^3.0.3: merge2 "^1.2.3" micromatch "^4.0.2" -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - fastq@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2" @@ -959,18 +811,6 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.2.2: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== -graphql-tag@^2.10.0: - version "2.10.1" - resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.1.tgz#10aa41f1cd8fae5373eaf11f1f67260a3cad5e02" - integrity sha512-jApXqWBzNXQ8jYa/HLkZJaVw9jgwNqZkywa2zfFn16Iv1Zb7ELNHkJaXHR7Quvd5SIGsy6Ny7SUKATgnu05uEg== - -graphql@^14.0.2: - version "14.4.2" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.4.2.tgz#553a7d546d524663eda49ed6df77577be3203ae3" - integrity sha512-6uQadiRgnpnSS56hdZUSvFrVcQ6OF9y6wkxJfKquFtHlnl7+KSuWwSJsdwiK1vybm1HgcdbpGkCpvhvsVQ0UZQ== - dependencies: - iterall "^1.2.2" - has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -983,13 +823,6 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= -hoist-non-react-statics@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" - integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== - dependencies: - react-is "^16.7.0" - hosted-git-info@^2.1.4: version "2.8.4" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.4.tgz#44119abaf4bc64692a16ace34700fed9c03e2546" @@ -1166,11 +999,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -iterall@^1.2.1, iterall@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7" - integrity sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -1293,11 +1121,6 @@ lodash._reinterpolate@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= -lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= - lodash.template@^4.0.2: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" @@ -1536,13 +1359,6 @@ opencollective-postinstall@^2.0.2: resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw== -optimism@^0.10.0: - version "0.10.2" - resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.10.2.tgz#626b6fd28b0923de98ecb36a3fd2d3d4e5632dd9" - integrity sha512-zPfBIxFFWMmQboM9+Z4MSJqc1PXp82v1PFq/GfQaufI69mHKlup7ykGNnfuGIGssXJQkmhSodQ/k9EWwjd8O8A== - dependencies: - "@wry/context" "^0.4.0" - p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -1699,7 +1515,7 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.6.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -1726,19 +1542,6 @@ quick-lru@^1.0.0: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= -react-apollo@^2.5.8: - version "2.5.8" - resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-2.5.8.tgz#c7a593b027efeefdd8399885e0ac6bec3b32623c" - integrity sha512-60yOQrnNosxU/tRbOxGDaYNLFcOKmQqxHPhxyvKTlGIaF/rRCXQRKixUgWVffpEupSHHD7psY5k5ZOuZsdsSGQ== - dependencies: - apollo-utilities "^1.3.0" - fast-json-stable-stringify "^2.0.0" - hoist-non-react-statics "^3.3.0" - lodash.isequal "^4.5.0" - prop-types "^15.7.2" - ts-invariant "^0.4.2" - tslib "^1.9.3" - react-dom@>=16.8.1: version "16.9.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.9.0.tgz#5e65527a5e26f22ae3701131bcccaee9fb0d3962" @@ -1749,7 +1552,7 @@ react-dom@>=16.8.1: prop-types "^15.6.2" scheduler "^0.15.0" -react-is@^16.7.0, react-is@^16.8.1: +react-is@^16.8.1: version "16.9.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.9.0.tgz#21ca9561399aad0ff1a7701c01683e8ca981edcb" integrity sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw== @@ -1803,25 +1606,6 @@ readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -reason-apollo@^0.17.0: - version "0.17.0" - resolved "https://registry.yarnpkg.com/reason-apollo/-/reason-apollo-0.17.0.tgz#44e5930028a26378dcc44fd3545dd36c84ab665b" - integrity sha512-3o0eit+uxkbRkkdzYnK+tV5oSWwmNWczT9qdSJKNCpu0R/NYE5qfpSBX7ouJUnE1j4arxgXDs2Ryey47QNYwrw== - dependencies: - apollo-cache-inmemory "^1.6.0" - apollo-client "^2.6.3" - apollo-link "^1.2.12" - apollo-link-context "^1.0.18" - apollo-link-error "^1.1.11" - apollo-link-http "^1.5.15" - apollo-link-ws "^1.0.18" - apollo-upload-client "9.1.0" - apollo-utilities "^1.3.2" - graphql "^14.0.2" - graphql-tag "^2.10.0" - react-apollo "^2.5.8" - subscriptions-transport-ws "^0.9.16" - reason-react@>=0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/reason-react/-/reason-react-0.7.0.tgz#46a975c321e81cd51310d7b1a02418ca7667b0d6" @@ -2086,17 +1870,6 @@ strip-indent@^2.0.0: resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= -subscriptions-transport-ws@^0.9.16: - version "0.9.16" - resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.16.tgz#90a422f0771d9c32069294c08608af2d47f596ec" - integrity sha512-pQdoU7nC+EpStXnCfh/+ho0zE0Z+ma+i7xvj7bkXKb1dvYHSZxgRPaU6spRP+Bjzow67c/rRDoix5RT0uU9omw== - dependencies: - backo2 "^1.0.2" - eventemitter3 "^3.1.0" - iterall "^1.2.1" - symbol-observable "^1.0.4" - ws "^5.2.0" - supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -2109,7 +1882,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -symbol-observable@^1.0.2, symbol-observable@^1.0.4, symbol-observable@^1.1.0: +symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== @@ -2149,7 +1922,7 @@ trim-off-newlines@^1.0.0: resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= -ts-invariant@^0.4.0, ts-invariant@^0.4.2, ts-invariant@^0.4.4: +ts-invariant@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86" integrity sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA== @@ -2199,13 +1972,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -ws@^5.2.0: - version "5.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" - integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== - dependencies: - async-limiter "~1.0.0" - xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -2217,16 +1983,3 @@ yargs-parser@^10.0.0: integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== dependencies: camelcase "^4.1.0" - -zen-observable-ts@^0.8.19: - version "0.8.19" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.19.tgz#c094cd20e83ddb02a11144a6e2a89706946b5694" - integrity sha512-u1a2rpE13G+jSzrg3aiCqXU5tN2kw41b+cBZGmnc+30YimdkKiDj9bTowcB41eL77/17RF/h+393AuVgShyheQ== - dependencies: - tslib "^1.9.3" - zen-observable "^0.8.0" - -zen-observable@^0.8.0: - version "0.8.14" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.14.tgz#d33058359d335bc0db1f0af66158b32872af3bf7" - integrity sha512-kQz39uonEjEESwh+qCi83kcC3rZJGh4mrZW7xjkSQYXkq//JZHTtKo+6yuVloTgMtzsIWOJrjIrKvk/dqm0L5g== From 832b9ae4cad4140fb8762c0c5d5c89967be2959f Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Mon, 13 Apr 2020 14:53:58 +0800 Subject: [PATCH 03/13] Raw t --- src/ApolloClient.re | 32 +++---- src/ApolloHooks.re | 6 +- src/ApolloHooksClient.re | 7 +- src/ApolloHooksMutation.re | 73 ++++++++------- src/ApolloHooksProvider.re | 5 +- src/ApolloHooksQuery.re | 163 +++------------------------------ src/ApolloHooksSubscription.re | 29 +++--- src/ApolloHooksTypes.re | 4 +- src/ReasonApolloTypes.re | 7 +- 9 files changed, 98 insertions(+), 228 deletions(-) diff --git a/src/ApolloClient.re b/src/ApolloClient.re index b9c6344..b0055f9 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -36,34 +36,29 @@ type fetchMoreOptions = { updateQuery: updateQueryT, }; -type queryResult = { +type queryResult('raw_t) = { loading: bool, - data: Js.Nullable.t(Js.Json.t), + data: Js.Nullable.t('raw_t), error: Js.Nullable.t(apolloError), - refetch: Js.Null_undefined.t(Js.Json.t) => Js.Promise.t(queryResult), + refetch: Js.Null_undefined.t('raw_t) => Js.Promise.t(queryResult('raw_t)), networkStatus: Js.Nullable.t(int), variables: Js.Null_undefined.t(Js.Json.t), fetchMore: fetchMoreOptions => Js.Promise.t(unit), subscribeToMore: subscribeToMoreOptions => unit, }; -type mutationResult = { +type mutationResult('raw_t) = { loading: bool, called: bool, - data: Js.Nullable.t(Js.Json.t), + data: Js.Nullable.t('raw_t), error: Js.Nullable.t(apolloError), networkStatus: Js.Nullable.t(int), variables: Js.Null_undefined.t(Js.Json.t), }; - -type generatedApolloClient = { - query: - [@bs.meth] (queryObj => Js.Promise.t(queryResult)), - mutate: - [@bs.meth] ( - mutationObj => Js.Promise.t(mutationResult) - ), +type generatedApolloClient('raw_t) = { + query: [@bs.meth] (queryObj => Js.Promise.t(queryResult('raw_t))), + mutate: [@bs.meth] (mutationObj => Js.Promise.t(mutationResult('raw_t))), resetStore: [@bs.meth] (unit => Js.Promise.t(unit)), }; @@ -77,7 +72,8 @@ type apolloClientObjectParam = { }; [@bs.module "@apollo/client"] [@bs.new] -external createApolloClientJS: apolloClientObjectParam => generatedApolloClient = +external createApolloClientJS: + apolloClientObjectParam => generatedApolloClient('raw_t) = "ApolloClient"; [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; @@ -90,11 +86,12 @@ module ReadQuery = (Config: ReasonApolloTypes.Config) => { type response = option(Config.t); [@bs.send] external readQuery: - (generatedApolloClient, readQueryOptions) => Js.Nullable.t(Js.Json.t) = + (generatedApolloClient('raw_t), readQueryOptions) => + Js.Nullable.t('raw_t) = "readQuery"; let graphqlQueryAST = gql(. Config.query); - let apolloDataToRecord: Js.Nullable.t(Js.Json.t) => response = + let apolloDataToRecord: Js.Nullable.t('raw_t) => response = apolloData => Js.Nullable.toOption(apolloData)->(Belt.Option.map(Config.parse)); @@ -113,7 +110,8 @@ module WriteQuery = (Config: ReasonApolloTypes.Config) => { data: Config.t, }; [@bs.send] - external writeQuery: (generatedApolloClient, writeQueryOptions) => unit = + external writeQuery: + (generatedApolloClient('raw_t), writeQueryOptions) => unit = "writeQuery"; let graphqlQueryAST = gql(. Config.query); diff --git a/src/ApolloHooks.re b/src/ApolloHooks.re index f98789f..eb828b3 100644 --- a/src/ApolloHooks.re +++ b/src/ApolloHooks.re @@ -4,7 +4,6 @@ module Provider = ApolloHooksProvider; module Subscription = ApolloHooksSubscription; let useQuery = Query.useQuery; -let useLazyQuery = Query.useLazyQuery; let useMutation = Mutation.useMutation; let useSubscription = Subscription.useSubscription; @@ -13,6 +12,11 @@ let toQueryObj = (result): ApolloClient.queryObj => { variables: result##variables, }; +let toQueryObj2 = (query, variables): ApolloClient.queryObj => { + query: ApolloClient.gql(. query), + variables, +}; + let toReadQueryOptions = result => { "query": ApolloClient.gql(. result##query), "variables": Js.Nullable.fromOption(Some(result##variables)), diff --git a/src/ApolloHooksClient.re b/src/ApolloHooksClient.re index 4b5c52a..b77c116 100644 --- a/src/ApolloHooksClient.re +++ b/src/ApolloHooksClient.re @@ -23,8 +23,7 @@ external doMakeOptions: ~pollInterval: int=?, unit ) => - options('data) = - ""; + options('data); let makeOptions = ( @@ -48,9 +47,9 @@ let makeOptions = [@bs.send] external query: - (ApolloClient.generatedApolloClient, options('data)) => + (ApolloClient.generatedApolloClient('raw_t), options('data)) => Js.Promise.t(queryResult('data)) = "query"; [@bs.module "../../../apolloClient"] -external client: ApolloClient.generatedApolloClient = "default"; +external client: ApolloClient.generatedApolloClient('raw_t) = "default"; diff --git a/src/ApolloHooksMutation.re b/src/ApolloHooksMutation.re index 9f91b8f..692b850 100644 --- a/src/ApolloHooksMutation.re +++ b/src/ApolloHooksMutation.re @@ -6,8 +6,8 @@ type error = { "graphqlErrors": graphqlErrors, }; -type refetchQueries = - ReasonApolloTypes.executionResult => array(ApolloClient.queryObj); +type refetchQueries('raw_t) = + ReasonApolloTypes.executionResult('raw_t) => array(ApolloClient.queryObj); /* Result that is return by the hook */ type result('a) = @@ -16,88 +16,91 @@ type result('a) = | NoData; /* Result that is return by the hook */ -type controlledResult('a) = { +type controlledResult('t) = { loading: bool, called: bool, - data: option('a), + data: option('t), error: option(error), }; type optimisticResult; -type controlledVariantResult('a) = +type controlledVariantResult('t) = | Loading | Called - | Data('a) + | Data('t) | Error(error) | NoData; [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; -type mutationResult('a) = {. "data": option('a)}; +type mutationResult('raw_t) = {. "data": option('raw_t)}; [@bs.deriving abstract] -type options('a) = { +type options('raw_t) = { [@bs.optional] variables: Js.Json.t, [@bs.optional] mutation: option(ReasonApolloTypes.queryString), [@bs.optional] - client: ApolloClient.generatedApolloClient, + client: ApolloClient.generatedApolloClient('raw_t), [@bs.optional] - refetchQueries, + refetchQueries: refetchQueries('raw_t), [@bs.optional] awaitRefetchQueries: bool, [@bs.optional] - update: (ApolloClient.generatedApolloClient, mutationResult('a)) => unit, + update: + (ApolloClient.generatedApolloClient('raw_t), mutationResult('raw_t)) => + unit, [@bs.optional] optimisticResponse: optimisticResult, }; -type jsResult = { +type jsResult('raw_t) = { . - "data": Js.Nullable.t(Js.Json.t), + "data": Js.Nullable.t('raw_t), "loading": bool, "called": bool, "error": Js.Nullable.t(error), }; -type jsMutate('a) = (. options('a)) => Js.Promise.t(jsResult); -type mutation('a) = +type jsMutate('raw_t) = + (. options('raw_t)) => Js.Promise.t(jsResult('raw_t)); +type mutation('t, 'raw_t) = ( ~variables: Js.Json.t=?, - ~client: ApolloClient.generatedApolloClient=?, - ~refetchQueries: refetchQueries=?, + ~client: ApolloClient.generatedApolloClient('raw_t)=?, + ~refetchQueries: refetchQueries('raw_t)=?, ~awaitRefetchQueries: bool=?, ~optimisticResponse: optimisticResult=?, unit ) => - Js.Promise.t(controlledVariantResult('a)); + Js.Promise.t(controlledVariantResult('t)); [@bs.module "@apollo/client"] external useMutationJs: - (. ReasonApolloTypes.queryString, options('a)) => (jsMutate('a), jsResult) = + (. ReasonApolloTypes.queryString, options('raw_t)) => + (jsMutate('raw_t), jsResult('raw_t)) = "useMutation"; exception Error(string); let useMutation: - type t. - ( - ~client: ApolloClient.generatedApolloClient=?, - ~variables: Js.Json.t=?, - ~refetchQueries: refetchQueries=?, - ~awaitRefetchQueries: bool=?, - ~update: (ApolloClient.generatedApolloClient, mutationResult(t)) => unit - =?, - ~optimisticResponse: optimisticResult=?, - ApolloHooksTypes.graphqlDefinition('data, _, _) - ) => - ( - mutation('data), - controlledVariantResult('data), - controlledResult('data), - ) = + ( + ~client: ApolloClient.generatedApolloClient('raw_t)=?, + ~variables: Js.Json.t=?, + ~refetchQueries: refetchQueries('raw_t)=?, + ~awaitRefetchQueries: bool=?, + ~update: ( + ApolloClient.generatedApolloClient('raw_t), + mutationResult('raw_t) + ) => + unit + =?, + ~optimisticResponse: optimisticResult=?, + ApolloHooksTypes.graphqlDefinition('t, 'raw_t, _) + ) => + (mutation('t, 'raw_t), controlledVariantResult('t), controlledResult('t)) = ( ~client=?, ~variables=?, diff --git a/src/ApolloHooksProvider.re b/src/ApolloHooksProvider.re index 6a050c1..2a78c11 100644 --- a/src/ApolloHooksProvider.re +++ b/src/ApolloHooksProvider.re @@ -1,5 +1,8 @@ [@bs.module "@apollo/client"] [@react.component] external make: - (~client: ApolloClient.generatedApolloClient, ~children: React.element) => + ( + ~client: ApolloClient.generatedApolloClient('raw_t), + ~children: React.element + ) => React.element = "ApolloProvider"; diff --git a/src/ApolloHooksQuery.re b/src/ApolloHooksQuery.re index b9ff8d5..a7a5503 100644 --- a/src/ApolloHooksQuery.re +++ b/src/ApolloHooksQuery.re @@ -46,11 +46,11 @@ type fetchMoreOptions('a) = { [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; [@bs.deriving abstract] -type options = { +type options('raw_t) = { [@bs.optional] variables: Js.Json.t, [@bs.optional] - client: ApolloClient.generatedApolloClient, + client: ApolloClient.generatedApolloClient('raw_t), [@bs.optional] notifyOnNetworkStatusChange: bool, [@bs.optional] @@ -63,16 +63,19 @@ type options = { pollInterval: int, }; +type refetchResult('raw_t) = {data: Js.Nullable.t('raw_t)}; + [@bs.module "@apollo/client"] external useQueryJs: - (ReasonApolloTypes.queryString, options) => + (ReasonApolloTypes.queryString, options('raw_t)) => { . - "data": Js.Nullable.t(Js.Json.t), + "data": Js.Nullable.t('raw_t), "loading": bool, "error": Js.Nullable.t(queryError), [@bs.meth] - "refetch": Js.Nullable.t(Js.Json.t) => Js.Promise.t(Js.Json.t), + "refetch": + Js.Nullable.t(Js.Json.t) => Js.Promise.t(refetchResult('raw_t)), [@bs.meth] "fetchMore": fetchMoreOptions('a) => Js.Promise.t(unit), "networkStatus": Js.Nullable.t(int), } = @@ -80,16 +83,16 @@ external useQueryJs: let useQuery: ( - ~client: ApolloClient.generatedApolloClient=?, + ~client: ApolloClient.generatedApolloClient('raw_t)=?, ~variables: Js.Json.t=?, ~notifyOnNetworkStatusChange: bool=?, ~fetchPolicy: ApolloHooksTypes.fetchPolicy=?, ~errorPolicy: ApolloHooksTypes.errorPolicy=?, ~skip: bool=?, ~pollInterval: int=?, - graphqlDefinition('data, _, _) + graphqlDefinition('t, 'raw_t, _) ) => - (variant('data), queryResult('data)) = + (variant('t), queryResult('t)) = ( ~client=?, ~variables=?, @@ -117,23 +120,17 @@ let useQuery: ), ); - let getData = obj => - obj - ->Js.Json.decodeObject - ->Belt.Option.flatMap(x => Js.Dict.get(x, "data")) - ->Belt.Option.getExn; - let data = React.useMemo1( () => jsResult##data ->Js.Nullable.toOption - ->Belt.Option.flatMap(data => + ->Belt.Option.flatMap(data => { switch (parse(data)) { | parsedData => Some(parsedData) | exception _ => None } - ), + }), [|jsResult|], ); @@ -146,7 +143,8 @@ let useQuery: refetch: (~variables=?, ()) => jsResult##refetch(Js.Nullable.fromOption(variables)) |> Js.Promise.then_(result => - parse(result->getData) |> Js.Promise.resolve + parse(result.data->Js.Nullable.toOption->Belt.Option.getExn) + |> Js.Promise.resolve ), fetchMore: (~variables=?, ~updateQuery, ()) => jsResult##fetchMore(fetchMoreOptions(~variables?, ~updateQuery, ())), @@ -166,134 +164,3 @@ let useQuery: (simple, result); }; - -type lazyVariant('a) = - | Data('a) - | Error(queryError) - | Loading - | NoData - | NotCalled; - -type lazyQueryResult('a) = { - called: bool, - data: option('a), - loading: bool, - error: option(queryError), - refetch: refetch('a), - fetchMore: - (~variables: Js.Json.t=?, ~updateQuery: updateQueryT('a), unit) => - Js.Promise.t(unit), - networkStatus: ApolloHooksTypes.networkStatus, -}; - -[@bs.module "@apollo/client"] -external useLazyQueryJs: - (ReasonApolloTypes.queryString, options) => - ( - unit => unit, - { - . - "data": Js.Nullable.t(Js.Json.t), - "loading": bool, - "error": Js.Nullable.t(queryError), - [@bs.meth] - "refetch": Js.Nullable.t(Js.Json.t) => Js.Promise.t(Js.Json.t), - [@bs.meth] "fetchMore": fetchMoreOptions('a) => Js.Promise.t(unit), - "networkStatus": Js.Nullable.t(int), - "called": bool, - }, - ) = - "useLazyQuery"; - -let useLazyQuery: - ( - ~client: ApolloClient.generatedApolloClient=?, - ~variables: Js.Json.t=?, - ~notifyOnNetworkStatusChange: bool=?, - ~fetchPolicy: ApolloHooksTypes.fetchPolicy=?, - ~errorPolicy: ApolloHooksTypes.errorPolicy=?, - ~skip: bool=?, - ~pollInterval: int=?, - graphqlDefinition('data, _, _) - ) => - (unit => unit, lazyVariant('data), lazyQueryResult('data)) = - ( - ~client=?, - ~variables=?, - ~notifyOnNetworkStatusChange=?, - ~fetchPolicy=?, - ~errorPolicy=?, - ~skip=?, - ~pollInterval=?, - (parse, query, _), - ) => { - let (load, jsResult) = - useLazyQueryJs( - gql(. query), - options( - ~variables?, - ~client?, - ~notifyOnNetworkStatusChange?, - ~fetchPolicy=? - fetchPolicy->Belt.Option.map(ApolloHooksTypes.fetchPolicyToJs), - ~errorPolicy=? - errorPolicy->Belt.Option.map(ApolloHooksTypes.errorPolicyToJs), - ~skip?, - ~pollInterval?, - (), - ), - ); - - let parse = Config.parse; - let getData = obj => - obj - ->Js.Json.decodeObject - ->Belt.Option.flatMap(x => Js.Dict.get(x, "data")) - ->Belt.Option.getExn; - - let result = - React.useMemo1( - () => - { - data: - jsResult##data - ->Js.Nullable.toOption - ->Belt.Option.flatMap(data => - switch (parse(data)) { - | parsedData => Some(parsedData) - | exception _ => None - } - ), - loading: jsResult##loading, - error: jsResult##error->Js.Nullable.toOption, - networkStatus: - ApolloHooksTypes.toNetworkStatus(jsResult##networkStatus), - refetch: (~variables=?, ()) => - jsResult##refetch(Js.Nullable.fromOption(variables)) - |> Js.Promise.then_(result => - parse(result->getData) |> Js.Promise.resolve - ), - fetchMore: (~variables=?, ~updateQuery, ()) => - jsResult##fetchMore( - fetchMoreOptions(~variables?, ~updateQuery, ()), - ), - called: jsResult##called, - }, - [|jsResult|], - ); - - let simple = - React.useMemo1( - () => - switch (result) { - | {loading: true} => Loading - | {error: Some(error)} => Error(error) - | {data: Some(data)} => Data(data) - | {called: false} => NotCalled - | _ => NoData - }, - [|result|], - ); - - (simple, result); - }; diff --git a/src/ApolloHooksSubscription.re b/src/ApolloHooksSubscription.re index 1f263db..09993a1 100644 --- a/src/ApolloHooksSubscription.re +++ b/src/ApolloHooksSubscription.re @@ -16,7 +16,7 @@ type result('a) = { [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; [@bs.deriving abstract] -type options = { +type options('raw_t) = { [@bs.optional] variables: Js.Json.t, [@bs.optional] @@ -24,12 +24,12 @@ type options = { [@bs.optional] onSubscriptionData: unit => unit, [@bs.optional] - client: ApolloClient.generatedApolloClient, + client: ApolloClient.generatedApolloClient('raw_t), }; [@bs.module "@apollo/client"] external useSubscription: - (ReasonApolloTypes.queryString, options) => + (ReasonApolloTypes.queryString, options('raw_t)) => { . "data": Js.Nullable.t(Js.Json.t), @@ -39,23 +39,18 @@ external useSubscription: "useSubscription"; let useSubscription: - - ( - ~variables: Js.Json.t=?, - ~client: ApolloClient.generatedApolloClient=?, - graphqlDefinition('data, _, _) - ) => - (variant('data), result('data)) = - (~variables=?, ~client=?, (parse, query, _)) => { + ( + ~variables: Js.Json.t=?, + ~client: ApolloClient.generatedApolloClient('raw_t)=?, + graphqlDefinition('t, 'raw_t, _) + ) => + (variant('t), result('t)) = + (~variables=?, ~client=?, (parse, query, _)) => { let jsResult = - useSubscription( - gql(. query), - options(~variables?, ~client?, ()), - ); + useSubscription(gql(. query), options(~variables?, ~client?, ())); let result = { - data: - jsResult##data->Js.Nullable.toOption->Belt.Option.map(parse), + data: jsResult##data->Js.Nullable.toOption->Belt.Option.map(parse), loading: jsResult##loading, error: jsResult##error->Js.Nullable.toOption, }; diff --git a/src/ApolloHooksTypes.re b/src/ApolloHooksTypes.re index 9ab6985..cc23115 100644 --- a/src/ApolloHooksTypes.re +++ b/src/ApolloHooksTypes.re @@ -61,7 +61,7 @@ let errorPolicyToJs = errorPolicy => | All => "all" }; -type parse('a) = Js.Json.t => 'a; +type parse('raw_t, 't) = 'raw_t => 't; type query = string; -type graphqlDefinition('data, 'b, 'c) = (parse('data), query, 'b); +type graphqlDefinition('t, 'raw_t, 'b) = (parse('raw_t, 't), query, 'b); diff --git a/src/ReasonApolloTypes.re b/src/ReasonApolloTypes.re index 2109874..143fe8d 100644 --- a/src/ReasonApolloTypes.re +++ b/src/ReasonApolloTypes.re @@ -31,15 +31,16 @@ type graphqlError = { nodes: Js.Nullable.t(array(string)), }; -type executionResult = { +type executionResult('raw_t) = { errors: Js.Nullable.t(Js.Array.t(graphqlError)), - data: Js.Nullable.t(Js.Json.t), + data: Js.Nullable.t('raw_t), }; module type Config = { let query: string; type t; - let parse: Js.Json.t => t; + module Raw: {type t;}; + let parse: Raw.t => t; }; type apolloError = { From 55c801be77338c4259a75ccda2a4d4253c6eb8fa Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Mon, 13 Apr 2020 16:40:38 +0800 Subject: [PATCH 04/13] improvements --- src/ApolloHooksClient.re | 2 +- src/ApolloHooksMutation.re | 73 ++++++++++++++++++---------------- src/ApolloHooksQuery.re | 2 +- src/ApolloHooksSubscription.re | 2 +- src/ApolloHooksTypes.re | 8 +--- 5 files changed, 43 insertions(+), 44 deletions(-) diff --git a/src/ApolloHooksClient.re b/src/ApolloHooksClient.re index 4bb14a1..b77c116 100644 --- a/src/ApolloHooksClient.re +++ b/src/ApolloHooksClient.re @@ -32,7 +32,7 @@ let makeOptions = ~fetchPolicy=?, ~errorPolicy=?, ~pollInterval=?, - (_, query, _): graphqlDefinition('data, _, _, _), + (_, query, _): graphqlDefinition('data, _, _), ) => { doMakeOptions( ~query=gql(. query), diff --git a/src/ApolloHooksMutation.re b/src/ApolloHooksMutation.re index 9fa2900..3a4bed2 100644 --- a/src/ApolloHooksMutation.re +++ b/src/ApolloHooksMutation.re @@ -8,25 +8,27 @@ type jsResult('raw_t) = { "error": Js.Nullable.t(apolloError), }; -type jsExecutionResult('raw_t) = { - . - "data": Js.Nullable.t('raw_t), - "errors": Js.Nullable.t(array(graphqlError)), -}; +module Execution = { + type jsExecutionResult('raw_t) = { + . + "data": Js.Nullable.t('raw_t), + "errors": Js.Nullable.t(array(graphqlError)), + }; -type refetchQueries('raw_t) = - jsExecutionResult('raw_t) => array(ApolloClient.queryObj); + type refetchQueries('raw_t) = + jsExecutionResult('raw_t) => array(ApolloClient.queryObj); -/* The type that the promise returned by the mutate function resolves to */ -type executionResult('a) = { - data: option('a), - errors: option(array(graphqlError)), -}; + /* The type that the promise returned by the mutate function resolves to */ + type executionResult('a) = { + data: option('a), + errors: option(array(graphqlError)), + }; -type executionVariantResult('a) = - | Data('a) - | Errors(array(graphqlError)) - | NoData; + type executionVariantResult('a) = + | Data('a) + | Errors(array(graphqlError)) + | NoData; +}; /* The type of the 'full' result returned by the hook */ type controlledResult('t) = { @@ -59,7 +61,7 @@ type options('raw_t) = { [@bs.optional] client: ApolloClient.generatedApolloClient('raw_t), [@bs.optional] - refetchQueries: refetchQueries('raw_t), + refetchQueries: Execution.refetchQueries('raw_t), [@bs.optional] awaitRefetchQueries: bool, [@bs.optional] @@ -71,18 +73,20 @@ type options('raw_t) = { }; type jsMutate('raw_t) = - (. options('raw_t)) => Js.Promise.t(jsExecutionResult('raw_t)); + (. options('raw_t)) => Js.Promise.t(Execution.jsExecutionResult('raw_t)); type mutation('t, 'raw_t) = ( ~variables: Js.Json.t=?, ~client: ApolloClient.generatedApolloClient('raw_t)=?, - ~refetchQueries: refetchQueries('raw_t)=?, + ~refetchQueries: Execution.refetchQueries('raw_t)=?, ~awaitRefetchQueries: bool=?, ~optimisticResponse: optimisticResult=?, unit ) => - Js.Promise.t((executionVariantResult('t), executionResult('t))); + Js.Promise.t( + (Execution.executionVariantResult('t), Execution.executionResult('t)), + ); [@bs.module "@apollo/client"] external useMutationJs: @@ -96,7 +100,7 @@ let useMutation: ( ~client: ApolloClient.generatedApolloClient('raw_t)=?, ~variables: Js.Json.t=?, - ~refetchQueries: refetchQueries('raw_t)=?, + ~refetchQueries: Execution.refetchQueries('raw_t)=?, ~awaitRefetchQueries: bool=?, ~update: ( ApolloClient.generatedApolloClient('raw_t), @@ -105,7 +109,7 @@ let useMutation: unit =?, ~optimisticResponse: optimisticResult=?, - ApolloHooksTypes.graphqlDefinition('t, 'raw_t, _, _) + ApolloHooksTypes.graphqlDefinition('t, 'raw_t, _) ) => (mutation('t, 'raw_t), controlledVariantResult('t), controlledResult('t)) = ( @@ -153,22 +157,23 @@ let useMutation: ), ) |> Js.Promise.then_(jsResult => { - let full = { - data: - Js.Nullable.toOption(jsResult##data) - ->Belt.Option.map(parse), - errors: - switch (Js.Nullable.toOption(jsResult##errors)) { - | Some(errors) when Js.Array.length(errors) > 0 => - Some(errors) - | _ => None - }, - }; + let full = + Execution.{ + data: + Js.Nullable.toOption(jsResult##data) + ->Belt.Option.map(parse), + errors: + switch (Js.Nullable.toOption(jsResult##errors)) { + | Some(errors) when Js.Array.length(errors) > 0 => + Some(errors) + | _ => None + }, + }; let simple = switch (full) { | {errors: Some(errors)} => ( - Errors(errors): executionVariantResult('data) + Errors(errors): Execution.executionVariantResult('data) ) | {data: Some(data)} => Data(data) | {errors: None, data: None} => NoData diff --git a/src/ApolloHooksQuery.re b/src/ApolloHooksQuery.re index 3474dd1..be8e3ea 100644 --- a/src/ApolloHooksQuery.re +++ b/src/ApolloHooksQuery.re @@ -128,7 +128,7 @@ let useQuery: ~skip: bool=?, ~pollInterval: int=?, ~context: Context.t=?, - graphqlDefinition('t, 'raw_t, _, _) + graphqlDefinition('t, 'raw_t, _) ) => (variant('t), queryResult('t)) = ( diff --git a/src/ApolloHooksSubscription.re b/src/ApolloHooksSubscription.re index eaa2c3b..5e5ab88 100644 --- a/src/ApolloHooksSubscription.re +++ b/src/ApolloHooksSubscription.re @@ -43,7 +43,7 @@ let useSubscription: ~variables: Js.Json.t=?, ~client: ApolloClient.generatedApolloClient('raw_t)=?, ~skip: bool=?, - ApolloHooksTypes.graphqlDefinition('t, 'raw_t, _, _) + ApolloHooksTypes.graphqlDefinition('t, 'raw_t, _) ) => (variant('t), result('t)) = (~variables=?, ~client=?, ~skip=?, (parse, query, _)) => { diff --git a/src/ApolloHooksTypes.re b/src/ApolloHooksTypes.re index c17279b..804d87a 100644 --- a/src/ApolloHooksTypes.re +++ b/src/ApolloHooksTypes.re @@ -85,14 +85,8 @@ type apolloError = { type parse('raw_t, 't) = 'raw_t => 't; type query = string; -type composeVariables('t, 'returnType, 'hookReturnType) = - ('t => 'returnType) => 'hookReturnType; -type graphqlDefinition('t, 'raw_t, 'returnType, 'hookReturnType) = ( - parse('raw_t, 't), - query, - composeVariables('t, 'returnType, 'hookReturnType), -); +type graphqlDefinition('t, 'raw_t, 'b) = (parse('raw_t, 't), query, 'b); module Context = { type t = Js.Dict.t(string); From 4ebe66d2914a070df7e6c95bd1358aa49de572b1 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Wed, 29 Apr 2020 14:45:44 +0800 Subject: [PATCH 05/13] add new types to make compatible with serialize functionality --- src/ApolloClient.re | 84 +++++++++++------- src/ApolloHooks.re | 20 ++--- src/ApolloHooksClient.re | 11 ++- src/ApolloHooksMutation.re | 70 ++++++++------- src/ApolloHooksProvider.re | 6 +- src/ApolloHooksQuery.re | 151 +++++++++++++++++++++------------ src/ApolloHooksSubscription.re | 10 +-- src/ApolloHooksTypes.re | 7 +- src/ReasonApolloTypes.re | 7 +- 9 files changed, 217 insertions(+), 149 deletions(-) diff --git a/src/ApolloClient.re b/src/ApolloClient.re index b0055f9..d0b6b57 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -1,22 +1,28 @@ open ReasonApolloTypes; -type queryObj = { +type queryObj('raw_t_variables) = { query: ReasonApolloTypes.queryString, - variables: Js.Json.t, + variables: 'raw_t_variables, }; -type mutationObj = { +type opaqueQueryObj; +external toOpaqueQueryObj: queryObj('raw_t_variables) => opaqueQueryObj = + "%identity"; + +type mutationObj('raw_t_variables) = { mutation: ReasonApolloTypes.queryString, - variables: Js.Json.t, + variables: 'raw_t_variables, }; -type updateQueryOptions = { - fetchMoreResult: option(Js.Json.t), - variables: option(Js.Json.t), +type updateQueryOptions('raw_t, 'raw_t_variables) = { + fetchMoreResult: option('raw_t), + variables: option('raw_t_variables), }; type onErrorT; -type updateQueryT = (Js.Json.t, updateQueryOptions) => Js.Json.t; +type updateQueryT('raw_t, 'raw_t_variables) = + ('raw_t, updateQueryOptions('raw_t, 'raw_t_variables)) => 'raw_t; + type updateSubscriptionOptions = { subscriptionData: option(Js.Json.t), variables: option(Js.Json.t), @@ -31,19 +37,22 @@ type subscribeToMoreOptions = { onError: option(onErrorT), }; -type fetchMoreOptions = { - variables: option(Js.Json.t), - updateQuery: updateQueryT, +type fetchMoreOptions('raw_t, 'raw_t_variables) = { + variables: option('raw_t_variables), + updateQuery: updateQueryT('raw_t, 'raw_t_variables), }; -type queryResult('raw_t) = { +type queryResult('raw_t, 'raw_t_variables) = { loading: bool, data: Js.Nullable.t('raw_t), error: Js.Nullable.t(apolloError), - refetch: Js.Null_undefined.t('raw_t) => Js.Promise.t(queryResult('raw_t)), + refetch: + Js.Null_undefined.t('raw_t) => + Js.Promise.t(queryResult('raw_t, 'raw_t_variables)), networkStatus: Js.Nullable.t(int), variables: Js.Null_undefined.t(Js.Json.t), - fetchMore: fetchMoreOptions => Js.Promise.t(unit), + fetchMore: + fetchMoreOptions('raw_t, 'raw_t_variables) => Js.Promise.t(unit), subscribeToMore: subscribeToMoreOptions => unit, }; @@ -56,11 +65,19 @@ type mutationResult('raw_t) = { variables: Js.Null_undefined.t(Js.Json.t), }; -type generatedApolloClient('raw_t) = { - query: [@bs.meth] (queryObj => Js.Promise.t(queryResult('raw_t))), - mutate: [@bs.meth] (mutationObj => Js.Promise.t(mutationResult('raw_t))), - resetStore: [@bs.meth] (unit => Js.Promise.t(unit)), -}; +type t; + +[@bs.send] +external query: + (t, queryObj('raw_t_variables)) => + Js.Promise.t(queryResult('raw_t, 'raw_t_variables)) = + "query"; + +[@bs.send] +external mutate: + (t, mutationObj('raw_t_variables)) => Js.Promise.t(mutationResult('raw_t)) = + "mutate"; +[@bs.send] external resetStore: t => Js.Promise.t(unit) = "resetStore"; type apolloClientObjectParam = { link: apolloLink, @@ -72,30 +89,26 @@ type apolloClientObjectParam = { }; [@bs.module "@apollo/client"] [@bs.new] -external createApolloClientJS: - apolloClientObjectParam => generatedApolloClient('raw_t) = - "ApolloClient"; +external createApolloClientJS: apolloClientObjectParam => t = "ApolloClient"; [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; module ReadQuery = (Config: ReasonApolloTypes.Config) => { type readQueryOptions = { query: ReasonApolloTypes.queryString, - variables: Js.Nullable.t(Js.Json.t), + variables: Js.Nullable.t(Config.Raw.t_variables), }; type response = option(Config.t); [@bs.send] - external readQuery: - (generatedApolloClient('raw_t), readQueryOptions) => - Js.Nullable.t('raw_t) = + external readQuery: (t, readQueryOptions) => Js.Nullable.t(Config.Raw.t) = "readQuery"; let graphqlQueryAST = gql(. Config.query); - let apolloDataToRecord: Js.Nullable.t('raw_t) => response = + let apolloDataToRecord: Js.Nullable.t(Config.Raw.t) => response = apolloData => Js.Nullable.toOption(apolloData)->(Belt.Option.map(Config.parse)); - let make = (~client, ~variables: option(Js.Json.t)=?, ()) => + let make = (~client, ~variables: option(Config.Raw.t_variables)=?, ()) => readQuery( client, {query: graphqlQueryAST, variables: Js.Nullable.fromOption(variables)}, @@ -106,17 +119,22 @@ module ReadQuery = (Config: ReasonApolloTypes.Config) => { module WriteQuery = (Config: ReasonApolloTypes.Config) => { type writeQueryOptions = { query: ReasonApolloTypes.queryString, - variables: Js.Nullable.t(Js.Json.t), + variables: Js.Nullable.t(Config.Raw.t_variables), data: Config.t, }; + [@bs.send] - external writeQuery: - (generatedApolloClient('raw_t), writeQueryOptions) => unit = - "writeQuery"; + external writeQuery: (t, writeQueryOptions) => unit = "writeQuery"; let graphqlQueryAST = gql(. Config.query); - let make = (~client, ~variables: option(Js.Json.t)=?, ~data: Config.t, ()) => + let make = + ( + ~client, + ~variables: option(Config.Raw.t_variables)=?, + ~data: Config.t, + (), + ) => writeQuery( client, { diff --git a/src/ApolloHooks.re b/src/ApolloHooks.re index 3837ee1..508b416 100644 --- a/src/ApolloHooks.re +++ b/src/ApolloHooks.re @@ -157,17 +157,17 @@ let toReadQueryOptions = result => { "variables": Js.Nullable.fromOption(Some(result##variables)), }; -external toOptimisticResult: 'a => Mutation.optimisticResult = "%identity"; - /** useSubscription bindings */ let useSubscription = Subscription.useSubscription; /** Helper to generate the shape of a query for [refetchQueries] mutation param. Take a look in examples/persons/src/EditPerson.re for a more complete demo of usage. */ -let toQueryObj = result => - ApolloClient.{ - query: ApolloClient.gql(. result##query), - variables: result##variables, - }; - -let toQueryObj2 = (query, variables) => - ApolloClient.{query: ApolloClient.gql(. query), variables}; +let toQueryObj: + (string, 'raw_t_variables) => ApolloClient.queryObj('raw_t_variables) = + (theQuery, variables) => + ApolloClient.{query: ApolloClient.gql(. theQuery), variables}; + +let toOpaqueQueryObj: (string, 'raw_t_variables) => ApolloClient.opaqueQueryObj = + (theQuery, variables) => + ApolloClient.toOpaqueQueryObj( + ApolloClient.{query: ApolloClient.gql(. theQuery), variables}, + ); diff --git a/src/ApolloHooksClient.re b/src/ApolloHooksClient.re index b77c116..77c90c6 100644 --- a/src/ApolloHooksClient.re +++ b/src/ApolloHooksClient.re @@ -16,7 +16,7 @@ type options('data); external doMakeOptions: ( ~query: ReasonApolloTypes.queryString, - ~variables: Js.Json.t=?, + ~variables: 'raw_t_variables=?, ~notifyOnNetworkStatusChange: bool=?, ~fetchPolicy: string=?, ~errorPolicy: string=?, @@ -27,12 +27,12 @@ external doMakeOptions: let makeOptions = ( - ~variables=?, + ~variables: 'raw_t_variables=?, ~notifyOnNetworkStatusChange=?, ~fetchPolicy=?, ~errorPolicy=?, ~pollInterval=?, - (_, query, _): graphqlDefinition('data, _, _), + (_, query, _): graphqlDefinition('data, _), ) => { doMakeOptions( ~query=gql(. query), @@ -47,9 +47,8 @@ let makeOptions = [@bs.send] external query: - (ApolloClient.generatedApolloClient('raw_t), options('data)) => - Js.Promise.t(queryResult('data)) = + (ApolloClient.t, options('data)) => Js.Promise.t(queryResult('data)) = "query"; [@bs.module "../../../apolloClient"] -external client: ApolloClient.generatedApolloClient('raw_t) = "default"; +external client: ApolloClient.t = "default"; diff --git a/src/ApolloHooksMutation.re b/src/ApolloHooksMutation.re index 3a4bed2..20cf4e0 100644 --- a/src/ApolloHooksMutation.re +++ b/src/ApolloHooksMutation.re @@ -16,7 +16,7 @@ module Execution = { }; type refetchQueries('raw_t) = - jsExecutionResult('raw_t) => array(ApolloClient.queryObj); + jsExecutionResult('raw_t) => array(ApolloClient.opaqueQueryObj); /* The type that the promise returned by the mutate function resolves to */ type executionResult('a) = { @@ -38,8 +38,6 @@ type controlledResult('t) = { error: option(apolloError), }; -type optimisticResult; - /* The type of the 'simple' result returned by the hook */ type controlledVariantResult('t) = | Loading @@ -53,35 +51,34 @@ type controlledVariantResult('t) = type mutationResult('raw_t) = {. "data": option('raw_t)}; [@bs.deriving abstract] -type options('raw_t) = { +type options('raw_t, 'raw_t_variables) = { [@bs.optional] - variables: Js.Json.t, + variables: 'raw_t_variables, [@bs.optional] mutation: option(ReasonApolloTypes.queryString), [@bs.optional] - client: ApolloClient.generatedApolloClient('raw_t), + client: ApolloClient.t, [@bs.optional] refetchQueries: Execution.refetchQueries('raw_t), [@bs.optional] awaitRefetchQueries: bool, [@bs.optional] - update: - (ApolloClient.generatedApolloClient('raw_t), mutationResult('raw_t)) => - unit, + update: (ApolloClient.t, mutationResult('raw_t)) => unit, [@bs.optional] - optimisticResponse: optimisticResult, + optimisticResponse: 'raw_t, }; -type jsMutate('raw_t) = - (. options('raw_t)) => Js.Promise.t(Execution.jsExecutionResult('raw_t)); +type jsMutate('raw_t, 'raw_t_variables) = + (. options('raw_t, 'raw_t_variables)) => + Js.Promise.t(Execution.jsExecutionResult('raw_t)); -type mutation('t, 'raw_t) = +type mutation('t, 'raw_t, 'raw_t_variables) = ( - ~variables: Js.Json.t=?, - ~client: ApolloClient.generatedApolloClient('raw_t)=?, + ~variables: 'raw_t_variables=?, + ~client: ApolloClient.t=?, ~refetchQueries: Execution.refetchQueries('raw_t)=?, ~awaitRefetchQueries: bool=?, - ~optimisticResponse: optimisticResult=?, + ~optimisticResponse: 't=?, unit ) => Js.Promise.t( @@ -90,28 +87,27 @@ type mutation('t, 'raw_t) = [@bs.module "@apollo/client"] external useMutationJs: - (. ReasonApolloTypes.queryString, options('raw_t)) => - (jsMutate('raw_t), jsResult('raw_t)) = + (. ReasonApolloTypes.queryString, options('raw_t, 'raw_t_variables)) => + (jsMutate('raw_t, 'raw_t_variables), jsResult('raw_t)) = "useMutation"; exception Error(string); let useMutation: ( - ~client: ApolloClient.generatedApolloClient('raw_t)=?, - ~variables: Js.Json.t=?, + ~client: ApolloClient.t=?, + ~variables: 'raw_t_variables=?, ~refetchQueries: Execution.refetchQueries('raw_t)=?, ~awaitRefetchQueries: bool=?, - ~update: ( - ApolloClient.generatedApolloClient('raw_t), - mutationResult('raw_t) - ) => - unit - =?, - ~optimisticResponse: optimisticResult=?, - ApolloHooksTypes.graphqlDefinition('t, 'raw_t, _) + ~update: (ApolloClient.t, mutationResult('raw_t)) => unit=?, + ~optimisticResponse: 't=?, + ApolloHooksTypes.graphqlDefinition('t, 'raw_t) ) => - (mutation('t, 'raw_t), controlledVariantResult('t), controlledResult('t)) = + ( + mutation('t, 'raw_t, 'raw_t_variables), + controlledVariantResult('t), + controlledResult('t), + ) = ( ~client=?, ~variables=?, @@ -119,7 +115,7 @@ let useMutation: ~awaitRefetchQueries=?, ~update=?, ~optimisticResponse=?, - (parse, query, _), + (parse, query, serialize), ) => { let (jsMutate, jsResult) = useMutationJs(. @@ -130,7 +126,12 @@ let useMutation: ~refetchQueries?, ~awaitRefetchQueries?, ~update?, - ~optimisticResponse?, + ~optimisticResponse=? + switch (optimisticResponse) { + | Some(optimisticResponse) => + Some(serialize(optimisticResponse)) + | None => None + }, (), ), ); @@ -152,7 +153,12 @@ let useMutation: ~client?, ~refetchQueries?, ~awaitRefetchQueries?, - ~optimisticResponse?, + ~optimisticResponse=? + switch (optimisticResponse) { + | Some(optimisticResponse) => + Some(serialize(optimisticResponse)) + | None => None + }, (), ), ) diff --git a/src/ApolloHooksProvider.re b/src/ApolloHooksProvider.re index 2a78c11..6341735 100644 --- a/src/ApolloHooksProvider.re +++ b/src/ApolloHooksProvider.re @@ -1,8 +1,4 @@ [@bs.module "@apollo/client"] [@react.component] external make: - ( - ~client: ApolloClient.generatedApolloClient('raw_t), - ~children: React.element - ) => - React.element = + (~client: ApolloClient.t, ~children: React.element) => React.element = "ApolloProvider"; diff --git a/src/ApolloHooksQuery.re b/src/ApolloHooksQuery.re index be8e3ea..42f0f08 100644 --- a/src/ApolloHooksQuery.re +++ b/src/ApolloHooksQuery.re @@ -6,83 +6,98 @@ type variant('a) = | Loading | NoData; -/** - * - * apollo-client/src/core/ObservableQuery.ts - */ -[@bs.deriving abstract] -type updateQueryOptions('a) = { - [@bs.optional] - fetchMoreResult: option('a), - [@bs.optional] - variables: Js.Json.t, -}; - -type updateQueryT('a) = ('a, updateQueryOptions('a)) => 'a; - /** * https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/watchQueryOptions.ts#L139 */ -type updateSubscriptionOptionsJs = { +type updateSubscriptionOptionsJs('raw_t, 'raw_t_variables) = { . - "subscriptionData": {. "data": Js.Json.t}, - "variables": Js.Nullable.t(Js.Json.t), + "subscriptionData": {. "data": 'raw_t}, + "variables": Js.Nullable.t('raw_t_variables), }; -type updateQuerySubscribeToMoreT = - (Js.Json.t, updateSubscriptionOptionsJs) => Js.Json.t; +type updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables) = + ('raw_t, updateSubscriptionOptionsJs('raw_t, 'raw_t_variables)) => 'raw_t; [@bs.deriving abstract] -type subscribeToMoreOptionsJs = { +type subscribeToMoreOptionsJs('raw_t, 'raw_t_variables) = { document: ReasonApolloTypes.queryString, [@bs.optional] - variables: Js.Json.t, + variables: 'raw_t_variables, [@bs.optional] - updateQuery: updateQuerySubscribeToMoreT, + updateQuery: updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables), }; type unsubscribeFnT = unit => unit; -type refetch('a) = (~variables: Js.Json.t=?, unit) => Js.Promise.t('a); -type queryResult('a) = { - data: option('a), +type updateQueryOptions('t, 'raw_t_variables) = { + fetchMoreResult: option('t), + variables: option('raw_t_variables), +}; + +module Raw = { + /** + * + * apollo-client/src/core/ObservableQuery.ts + */ + type updateQueryOptions('raw_t, 'raw_t_variables) = { + fetchMoreResult: Js.Nullable.t('raw_t), + variables: Js.Nullable.t('raw_t_variables), + }; + + /** + * apollo-client/src/core/watchQueryOptions.ts + */ + type fetchMoreOptions('raw_t, 'raw_t_variables) = { + variables: option('raw_t_variables), + updateQuery: + ('raw_t, updateQueryOptions('raw_t, 'raw_t_variables)) => 'raw_t, + }; +}; + +type queryResult('t, 'raw_t, 'raw_t_variables) = { + data: option('t), loading: bool, error: option(apolloError), - refetch: refetch('a), + networkStatus: ApolloHooksTypes.networkStatus, + refetch: (~variables: 'raw_t_variables=?, unit) => Js.Promise.t('t), fetchMore: - (~variables: Js.Json.t=?, ~updateQuery: updateQueryT('a), unit) => + ( + ~variables: 'raw_t_variables=?, + ~updateQuery: ('t, updateQueryOptions('t, 'raw_t_variables)) => 't, + unit + ) => + Js.Promise.t(unit), + rawFetchMore: + ( + ~variables: 'raw_t_variables=?, + ~updateQuery: ( + 'raw_t, + Raw.updateQueryOptions('raw_t, 'raw_t_variables) + ) => + 'raw_t, + unit + ) => Js.Promise.t(unit), - networkStatus: ApolloHooksTypes.networkStatus, startPolling: int => unit, stopPolling: unit => unit, subscribeToMore: ( ~document: ReasonApolloTypes.queryString, - ~variables: Js.Json.t=?, - ~updateQuery: updateQuerySubscribeToMoreT=?, + ~variables: 'raw_t_variables=?, + ~updateQuery: updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables)=?, unit ) => unsubscribeFnT, }; -/** - * apollo-client/src/core/watchQueryOptions.ts - */ -[@bs.deriving abstract] -type fetchMoreOptions('a) = { - [@bs.optional] - variables: Js.Json.t, - updateQuery: updateQueryT('a), -}; - [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; [@bs.deriving abstract] -type options('raw_t) = { +type options('raw_t_variables) = { [@bs.optional] - variables: Js.Json.t, + variables: 'raw_t_variables, [@bs.optional] - client: ApolloClient.generatedApolloClient('raw_t), + client: ApolloClient.t, [@bs.optional] notifyOnNetworkStatusChange: bool, [@bs.optional] @@ -101,7 +116,7 @@ type refetchResult('raw_t) = {data: Js.Nullable.t('raw_t)}; [@bs.module "@apollo/client"] external useQueryJs: - (ReasonApolloTypes.queryString, options('raw_t)) => + (ReasonApolloTypes.queryString, options('raw_t_variables)) => { . "data": Js.Nullable.t('raw_t), @@ -109,28 +124,32 @@ external useQueryJs: "error": Js.Nullable.t(apolloError), [@bs.meth] "refetch": - Js.Nullable.t(Js.Json.t) => Js.Promise.t(refetchResult('raw_t)), - [@bs.meth] "fetchMore": fetchMoreOptions('a) => Js.Promise.t(unit), + Js.Nullable.t('raw_t_variables) => Js.Promise.t(refetchResult('raw_t)), + [@bs.meth] + "fetchMore": + Raw.fetchMoreOptions('raw_t, 'raw_t_variables) => Js.Promise.t(unit), "networkStatus": Js.Nullable.t(int), [@bs.meth] "stopPolling": unit => unit, [@bs.meth] "startPolling": int => unit, - [@bs.meth] "subscribeToMore": subscribeToMoreOptionsJs => unsubscribeFnT, + [@bs.meth] + "subscribeToMore": + subscribeToMoreOptionsJs('raw_t, 'raw_t_variables) => unsubscribeFnT, } = "useQuery"; let useQuery: ( - ~client: ApolloClient.generatedApolloClient('raw_t)=?, - ~variables: Js.Json.t=?, + ~client: ApolloClient.t=?, + ~variables: 'raw_t_variables=?, ~notifyOnNetworkStatusChange: bool=?, ~fetchPolicy: ApolloHooksTypes.fetchPolicy=?, ~errorPolicy: ApolloHooksTypes.errorPolicy=?, ~skip: bool=?, ~pollInterval: int=?, ~context: Context.t=?, - graphqlDefinition('t, 'raw_t, _) + graphqlDefinition('t, 'raw_t) ) => - (variant('t), queryResult('t)) = + (variant('t), queryResult('t, 'raw_t, 'raw_t_variables)) = ( ~client=?, ~variables=?, @@ -140,7 +159,7 @@ let useQuery: ~skip=?, ~pollInterval=?, ~context=?, - (parse, query, _), + (parse, query, serialize), ) => { let jsResult = useQueryJs( @@ -185,10 +204,30 @@ let useQuery: ) |> Js.Promise.resolve ), - fetchMore: (~variables=?, ~updateQuery, ()) => - jsResult##fetchMore( - fetchMoreOptions(~variables?, ~updateQuery, ()), - ), + rawFetchMore: (~variables=?, ~updateQuery, ()) => + jsResult##fetchMore({Raw.variables, Raw.updateQuery}), + fetchMore: (~variables=?, ~updateQuery, ()) => { + jsResult##fetchMore({ + Raw.variables, + Raw.updateQuery: + (previousResult, {fetchMoreResult, variables}) => { + let result = + updateQuery( + parse(previousResult), + { + fetchMoreResult: + switch (Js.Nullable.toOption(fetchMoreResult)) { + | None => None + | Some(fetchMoreResult) => + Some(parse(fetchMoreResult)) + }, + variables: Js.Nullable.toOption(variables), + }, + ); + serialize(result); + }, + }); + }, stopPolling: () => jsResult##stopPolling(), startPolling: interval => jsResult##startPolling(interval), subscribeToMore: (~document, ~variables=?, ~updateQuery=?, ()) => diff --git a/src/ApolloHooksSubscription.re b/src/ApolloHooksSubscription.re index 5e5ab88..7d7c3ad 100644 --- a/src/ApolloHooksSubscription.re +++ b/src/ApolloHooksSubscription.re @@ -16,7 +16,7 @@ type result('a) = { [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; [@bs.deriving abstract] -type options('raw_t) = { +type options('raw_t, 'raw_t_variables) = { [@bs.optional] variables: Js.Json.t, [@bs.optional] @@ -24,12 +24,12 @@ type options('raw_t) = { [@bs.optional] onSubscriptionData: unit => unit, [@bs.optional] - client: ApolloClient.generatedApolloClient('raw_t), + client: ApolloClient.t, }; [@bs.module "@apollo/client"] external useSubscription: - (ReasonApolloTypes.queryString, options('raw_t)) => + (ReasonApolloTypes.queryString, options('raw_t, 'raw_t_variables)) => { . "data": Js.Nullable.t(Js.Json.t), @@ -41,9 +41,9 @@ external useSubscription: let useSubscription: ( ~variables: Js.Json.t=?, - ~client: ApolloClient.generatedApolloClient('raw_t)=?, + ~client: ApolloClient.t=?, ~skip: bool=?, - ApolloHooksTypes.graphqlDefinition('t, 'raw_t, _) + ApolloHooksTypes.graphqlDefinition('t, 'raw_t) ) => (variant('t), result('t)) = (~variables=?, ~client=?, ~skip=?, (parse, query, _)) => { diff --git a/src/ApolloHooksTypes.re b/src/ApolloHooksTypes.re index 804d87a..1bac2ba 100644 --- a/src/ApolloHooksTypes.re +++ b/src/ApolloHooksTypes.re @@ -84,9 +84,14 @@ type apolloError = { }; type parse('raw_t, 't) = 'raw_t => 't; +type serialize('t, 'raw_t) = 't => 'raw_t; type query = string; -type graphqlDefinition('t, 'raw_t, 'b) = (parse('raw_t, 't), query, 'b); +type graphqlDefinition('t, 'raw_t) = ( + parse('raw_t, 't), + query, + serialize('t, 'raw_t), +); module Context = { type t = Js.Dict.t(string); diff --git a/src/ReasonApolloTypes.re b/src/ReasonApolloTypes.re index 143fe8d..f160412 100644 --- a/src/ReasonApolloTypes.re +++ b/src/ReasonApolloTypes.re @@ -38,8 +38,13 @@ type executionResult('raw_t) = { module type Config = { let query: string; + module Raw: { + type t; + type t_variables; + }; type t; - module Raw: {type t;}; + type t_variables; + let parse: Raw.t => t; }; From 6e659bb6bc4ab345e5385a10de9b46f6d5360405 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Sat, 23 May 2020 15:39:41 +0800 Subject: [PATCH 06/13] Update to new graphql-ppx API --- src/ApolloClient.re | 312 +++++++++-------- src/ApolloClient_Client.re | 146 ++++++++ src/ApolloClient_HooksClient.re | 72 ++++ ...ksMutation.re => ApolloClient_Mutation.re} | 147 +++++--- ...ksProvider.re => ApolloClient_Provider.re} | 2 +- src/ApolloClient_Query.re | 329 ++++++++++++++++++ ...iption.re => ApolloClient_Subscription.re} | 13 +- ...lloHooksTypes.re => ApolloClient_Types.re} | 92 +++-- src/ApolloHooks.re | 173 --------- src/ApolloHooksClient.re | 54 --- src/ApolloHooksQuery.re | 259 -------------- src/ReasonApolloTypes.re | 55 --- src/index.mld | 2 +- 13 files changed, 903 insertions(+), 753 deletions(-) create mode 100644 src/ApolloClient_Client.re create mode 100644 src/ApolloClient_HooksClient.re rename src/{ApolloHooksMutation.re => ApolloClient_Mutation.re} (56%) rename src/{ApolloHooksProvider.re => ApolloClient_Provider.re} (51%) create mode 100644 src/ApolloClient_Query.re rename src/{ApolloHooksSubscription.re => ApolloClient_Subscription.re} (82%) rename src/{ApolloHooksTypes.re => ApolloClient_Types.re} (53%) delete mode 100644 src/ApolloHooks.re delete mode 100644 src/ApolloHooksClient.re delete mode 100644 src/ApolloHooksQuery.re delete mode 100644 src/ReasonApolloTypes.re diff --git a/src/ApolloClient.re b/src/ApolloClient.re index d0b6b57..6ba36a8 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -1,146 +1,176 @@ -open ReasonApolloTypes; - -type queryObj('raw_t_variables) = { - query: ReasonApolloTypes.queryString, - variables: 'raw_t_variables, -}; - -type opaqueQueryObj; -external toOpaqueQueryObj: queryObj('raw_t_variables) => opaqueQueryObj = - "%identity"; - -type mutationObj('raw_t_variables) = { - mutation: ReasonApolloTypes.queryString, - variables: 'raw_t_variables, -}; - -type updateQueryOptions('raw_t, 'raw_t_variables) = { - fetchMoreResult: option('raw_t), - variables: option('raw_t_variables), +module Mutation = ApolloClient_Mutation; +module Query = ApolloClient_Query; +module Provider = ApolloClient_Provider; +module Subscription = ApolloClient_Subscription; +module Client = ApolloClient_Client; + +/** + This is probably the one hook you'll use the most. A quick demo: + + {[ + open ApolloClient; + + module Query = [%graphql {| + query MyQuery { + me { id, name } + } + |}]; + + [@react.component] + let make = () => { + /* In Reason we prefix variables that we are not going to use with _ */ + let (simple, _full) = useQuery(Query.definitions); + + /* When using simple with Reason's pattern-matching operator, the compiler will force you to cover every single branch of the variant type */ + switch(simple) { + | Loading => React.string("loading...") + | Error(error) => + Js.log(error); + React.string("Something went wrong!") + | Data(data) => + React.string("Hello, " ++ data##me##name) + /* Every. Single. One. Of Them. */ + | NoData => + React.string("Woa something went really wrong! Glady we use Reason and it forced us to handle this! Report this issue") + } + } + ]} + + Why we return a tuple? While designing and using the API we came to the conclusion that would be much more convient to have a value that would attend + the majority of simple usages and a full for when you need to do a complex UI, such as infinite scroll. + + The value [simple] ({!type:Query.variant('a)}) helps you to consume your data with simplicity, type safety and exhaustiveness check. + But for those cases where you really want do do a fine-grained control of your data flow – such as when you have [loading] and [data] at the same time – + that's when [full] ({!type:Query.queryResult('a)}) becomes more useful. + + {[ + module Query = [%graphql {| + query MyQuery { + me { id, name } + } + |}]; + + [@react.component] + let make = () => { + let (_simple, full) = useQuery(Query.definitions); + + /* `full` is a record type so you pattern against it's possible combos of values */ + switch(full) { + /* Initial loading */ + | { loading: true, data: None } => React.string("loading...") + /* Error but no data */ + | { loading: false, data: None, error: Some(error) } => React.string("Something went wrong") + /* When we have some data and we tried to refetch but got an error */ + | { loading: false, data: Some(data), error: Some(error) } => + <> + {React.string("Something went wrong")} + + + /* Just data */ + | { loading: false, data: Some(data), error: None } => + <> + {React.string("Something went wrong")} + + + | Data(data) => + React.string("Hello, " ++ data##me##name) + /* Not loading? No data? No error? That's weird */ + | {loading: false, data: None, error: null} => + React.string("Woa something went really wrong! But the programmer remembered to handle this case! Report to us") + } + } + ]} + + Quite more complex right? Gladly it's not always that we have that level of complexity. + + That covers the most common cases of usage. If you want to see more complex usages check out the examples folder. + */ +let useQuery = Query.useQuery; +let useQueryLegacy = Query.useQueryLegacy; + +/** + Second most used! Here's a quick demo: + + {[ + open ApolloClient; + + module Mutation = [%graphql {| + mutation MyMutation($input: MyMutationInput!) { + myMutation(input: $input) { error } + } + |}]; + + [@react.component] + let make = () => { + /* `simple` and `full` follow the same principle of `useQuery`. */ + let (mutate, simple, _full) = useMutation(Mutation.definitions); + + /* When using simple with Reason's pattern-matching operator, the compiler will force you to cover every single branch of the variant type */ + switch(simple) { + | Loading => React.string("loading...") + | Error(error) => + Js.log(error); + React.string("Something went wrong!") + | Data(data) => +
+ {React.string("Hello, " ++ data##me##name)} +
+ /* Every. Single. One. Of Them. */ + | NotCalled => + } + ]} + */ +let useMutation = Mutation.useMutation; +let useMutationLegacy = Mutation.useMutationLegacy; + +let toReadQueryOptions = result => { + "query": Client.gql(. result##query), + "variables": Js.Nullable.fromOption(Some(result##variables)), }; -type onErrorT; -type updateQueryT('raw_t, 'raw_t_variables) = - ('raw_t, updateQueryOptions('raw_t, 'raw_t_variables)) => 'raw_t; +/** useSubscription bindings */ +let useSubscription = Subscription.useSubscription; -type updateSubscriptionOptions = { - subscriptionData: option(Js.Json.t), - variables: option(Js.Json.t), -}; -type updateQuerySubscriptionT = - (Js.Json.t, updateSubscriptionOptions) => Js.Json.t; - -type subscribeToMoreOptions = { - document: queryString, - variables: option(Js.Json.t), - updateQuery: option(updateQuerySubscriptionT), - onError: option(onErrorT), -}; - -type fetchMoreOptions('raw_t, 'raw_t_variables) = { - variables: option('raw_t_variables), - updateQuery: updateQueryT('raw_t, 'raw_t_variables), -}; +/** Helper to generate the shape of a query for [refetchQueries] mutation param. Take a look in examples/persons/src/EditPerson.re for a more complete demo of usage. */ +let toQueryObj: + (string, 'raw_t_variables) => Client.queryObj('raw_t_variables) = + (theQuery, variables) => + Client.{query: Client.gql(. theQuery), variables}; -type queryResult('raw_t, 'raw_t_variables) = { - loading: bool, - data: Js.Nullable.t('raw_t), - error: Js.Nullable.t(apolloError), - refetch: - Js.Null_undefined.t('raw_t) => - Js.Promise.t(queryResult('raw_t, 'raw_t_variables)), - networkStatus: Js.Nullable.t(int), - variables: Js.Null_undefined.t(Js.Json.t), - fetchMore: - fetchMoreOptions('raw_t, 'raw_t_variables) => Js.Promise.t(unit), - subscribeToMore: subscribeToMoreOptions => unit, -}; - -type mutationResult('raw_t) = { - loading: bool, - called: bool, - data: Js.Nullable.t('raw_t), - error: Js.Nullable.t(apolloError), - networkStatus: Js.Nullable.t(int), - variables: Js.Null_undefined.t(Js.Json.t), -}; - -type t; - -[@bs.send] -external query: - (t, queryObj('raw_t_variables)) => - Js.Promise.t(queryResult('raw_t, 'raw_t_variables)) = - "query"; - -[@bs.send] -external mutate: - (t, mutationObj('raw_t_variables)) => Js.Promise.t(mutationResult('raw_t)) = - "mutate"; -[@bs.send] external resetStore: t => Js.Promise.t(unit) = "resetStore"; - -type apolloClientObjectParam = { - link: apolloLink, - cache: apolloCache, - ssrMode: option(bool), - ssrForceFetchDelay: option(int), - connectToDevTools: option(bool), - queryDeduplication: option(bool), -}; - -[@bs.module "@apollo/client"] [@bs.new] -external createApolloClientJS: apolloClientObjectParam => t = "ApolloClient"; - -[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; - -module ReadQuery = (Config: ReasonApolloTypes.Config) => { - type readQueryOptions = { - query: ReasonApolloTypes.queryString, - variables: Js.Nullable.t(Config.Raw.t_variables), - }; - type response = option(Config.t); - [@bs.send] - external readQuery: (t, readQueryOptions) => Js.Nullable.t(Config.Raw.t) = - "readQuery"; - - let graphqlQueryAST = gql(. Config.query); - let apolloDataToRecord: Js.Nullable.t(Config.Raw.t) => response = - apolloData => - Js.Nullable.toOption(apolloData)->(Belt.Option.map(Config.parse)); - - let make = (~client, ~variables: option(Config.Raw.t_variables)=?, ()) => - readQuery( - client, - {query: graphqlQueryAST, variables: Js.Nullable.fromOption(variables)}, - ) - ->apolloDataToRecord; -}; - -module WriteQuery = (Config: ReasonApolloTypes.Config) => { - type writeQueryOptions = { - query: ReasonApolloTypes.queryString, - variables: Js.Nullable.t(Config.Raw.t_variables), - data: Config.t, - }; - - [@bs.send] - external writeQuery: (t, writeQueryOptions) => unit = "writeQuery"; - - let graphqlQueryAST = gql(. Config.query); - - let make = - ( - ~client, - ~variables: option(Config.Raw.t_variables)=?, - ~data: Config.t, - (), - ) => - writeQuery( - client, - { - query: graphqlQueryAST, - variables: Js.Nullable.fromOption(variables), - data, - }, +let toOpaqueQueryObj: (string, 'raw_t_variables) => Client.opaqueQueryObj = + (theQuery, variables) => + Client.toOpaqueQueryObj( + Client.{query: Client.gql(. theQuery), variables}, ); -}; diff --git a/src/ApolloClient_Client.re b/src/ApolloClient_Client.re new file mode 100644 index 0000000..4543708 --- /dev/null +++ b/src/ApolloClient_Client.re @@ -0,0 +1,146 @@ +module Types = ApolloClient_Types; + +type queryObj('raw_t_variables) = { + query: Types.queryString, + variables: 'raw_t_variables, +}; + +type opaqueQueryObj; +external toOpaqueQueryObj: queryObj('raw_t_variables) => opaqueQueryObj = + "%identity"; + +type mutationObj('raw_t_variables) = { + mutation: Types.queryString, + variables: 'raw_t_variables, +}; + +type updateQueryOptions('raw_t, 'raw_t_variables) = { + fetchMoreResult: option('raw_t), + variables: option('raw_t_variables), +}; + +type onErrorT; +type updateQueryT('raw_t, 'raw_t_variables) = + ('raw_t, updateQueryOptions('raw_t, 'raw_t_variables)) => 'raw_t; + +type updateSubscriptionOptions = { + subscriptionData: option(Js.Json.t), + variables: option(Js.Json.t), +}; +type updateQuerySubscriptionT = + (Js.Json.t, updateSubscriptionOptions) => Js.Json.t; + +type subscribeToMoreOptions = { + document: Types.queryString, + variables: option(Js.Json.t), + updateQuery: option(updateQuerySubscriptionT), + onError: option(onErrorT), +}; + +type fetchMoreOptions('raw_t, 'raw_t_variables) = { + variables: option('raw_t_variables), + updateQuery: updateQueryT('raw_t, 'raw_t_variables), +}; + +type queryResult('raw_t, 'raw_t_variables) = { + loading: bool, + data: Js.Nullable.t('raw_t), + error: Js.Nullable.t(Types.apolloError), + refetch: + Js.Null_undefined.t('raw_t) => + Js.Promise.t(queryResult('raw_t, 'raw_t_variables)), + networkStatus: Js.Nullable.t(int), + variables: Js.Null_undefined.t(Js.Json.t), + fetchMore: + fetchMoreOptions('raw_t, 'raw_t_variables) => Js.Promise.t(unit), + subscribeToMore: subscribeToMoreOptions => unit, +}; + +type mutationResult('raw_t) = { + loading: bool, + called: bool, + data: Js.Nullable.t('raw_t), + error: Js.Nullable.t(Types.apolloError), + networkStatus: Js.Nullable.t(int), + variables: Js.Null_undefined.t(Js.Json.t), +}; + +type t; + +[@bs.send] +external query: + (t, queryObj('raw_t_variables)) => + Js.Promise.t(queryResult('raw_t, 'raw_t_variables)) = + "query"; + +[@bs.send] +external mutate: + (t, mutationObj('raw_t_variables)) => Js.Promise.t(mutationResult('raw_t)) = + "mutate"; +[@bs.send] external resetStore: t => Js.Promise.t(unit) = "resetStore"; + +type apolloClientObjectParam = { + link: Types.apolloLink, + cache: Types.apolloCache, + ssrMode: option(bool), + ssrForceFetchDelay: option(int), + connectToDevTools: option(bool), + queryDeduplication: option(bool), +}; + +[@bs.module "@apollo/client"] [@bs.new] +external createApolloClientJS: apolloClientObjectParam => t = "ApolloClient"; + +[@bs.module "graphql-tag"] external gql: Types.gql = "default"; + +module ReadQuery = (Definition: Types.Definition) => { + type readQueryOptions = { + query: Types.queryString, + variables: Js.Nullable.t(Definition.Raw.t_variables), + }; + type response = option(Definition.t); + [@bs.send] + external readQuery: (t, readQueryOptions) => Js.Nullable.t(Definition.Raw.t) = + "readQuery"; + + let graphqlQueryAST = gql(. Definition.query); + let apolloDataToRecord: Js.Nullable.t(Definition.Raw.t) => response = + apolloData => + Js.Nullable.toOption(apolloData)->(Belt.Option.map(Definition.parse)); + + let make = (~client, ~variables: option(Definition.Raw.t_variables)=?, ()) => + readQuery( + client, + {query: graphqlQueryAST, variables: Js.Nullable.fromOption(variables)}, + ) + ->apolloDataToRecord; +}; + +module WriteQuery = (Definition: Types.Definition) => { + type writeQueryOptions = { + query: Types.queryString, + variables: Js.Nullable.t(Definition.Raw.t_variables), + data: Definition.t, + }; + + [@bs.send] + external writeQuery: (t, writeQueryOptions) => unit = "writeQuery"; + + let graphqlQueryAST = gql(. Definition.query); + + let make = + ( + ~client, + ~variables: option(Definition.Raw.t_variables)=?, + ~data: Definition.t, + (), + ) => + writeQuery( + client, + { + query: graphqlQueryAST, + variables: Js.Nullable.fromOption(variables), + data, + }, + ); +}; diff --git a/src/ApolloClient_HooksClient.re b/src/ApolloClient_HooksClient.re new file mode 100644 index 0000000..23f261f --- /dev/null +++ b/src/ApolloClient_HooksClient.re @@ -0,0 +1,72 @@ +module Types = ApolloClient_Types; + +type queryError = {. "message": string}; +type queryResult('a) = { + data: option('a), + errors: option(array(queryError)), + loading: bool, + networkStatus: Types.networkStatus, + stale: bool, +}; + +[@bs.module "graphql-tag"] external gql: Types.gql = "default"; + +type options('data); +[@bs.obj] +external doMakeOptions: + ( + ~query: Types.queryString, + ~variables: 'raw_t_variables=?, + ~notifyOnNetworkStatusChange: bool=?, + ~fetchPolicy: string=?, + ~errorPolicy: string=?, + ~pollInterval: int=?, + unit + ) => + options('data); + +let makeOptions: + type t raw_t raw_t_variables. + ( + ~variables: raw_t_variables=?, + ~notifyOnNetworkStatusChange: bool=?, + ~fetchPolicy: Types.fetchPolicy=?, + ~errorPolicy: Types.errorPolicy=?, + ~pollInterval: int=?, + ~context: Types.Context.t=?, + (module Types.Operation with + type t = t and + type Raw.t = raw_t and + type Raw.t_variables = raw_t_variables) + ) => + options(t) = + ( + ~variables=?, + ~notifyOnNetworkStatusChange=?, + ~fetchPolicy=?, + ~errorPolicy=?, + ~pollInterval=?, + ~context=?, + (module Definition), + ) => { + doMakeOptions( + ~query=gql(. Definition.query), + ~variables?, + ~notifyOnNetworkStatusChange?, + ~fetchPolicy=? + fetchPolicy->Belt.Option.map(f => Types.fetchPolicyToJs(f)), + ~errorPolicy=? + errorPolicy->Belt.Option.map(e => Types.errorPolicyToJs(e)), + ~pollInterval?, + (), + ); + }; + +[@bs.send] +external query: + (ApolloClient_Client.t, options('data)) => + Js.Promise.t(queryResult('data)) = + "query"; + +[@bs.module "../../../apolloClient"] +external client: ApolloClient_Client.t = "default"; diff --git a/src/ApolloHooksMutation.re b/src/ApolloClient_Mutation.re similarity index 56% rename from src/ApolloHooksMutation.re rename to src/ApolloClient_Mutation.re index 20cf4e0..2933041 100644 --- a/src/ApolloHooksMutation.re +++ b/src/ApolloClient_Mutation.re @@ -1,32 +1,32 @@ -open ApolloHooksTypes; +module Types = ApolloClient_Types; type jsResult('raw_t) = { . "data": Js.Nullable.t('raw_t), "loading": bool, "called": bool, - "error": Js.Nullable.t(apolloError), + "error": Js.Nullable.t(Types.apolloError), }; module Execution = { type jsExecutionResult('raw_t) = { . "data": Js.Nullable.t('raw_t), - "errors": Js.Nullable.t(array(graphqlError)), + "errors": Js.Nullable.t(array(Types.graphqlError)), }; type refetchQueries('raw_t) = - jsExecutionResult('raw_t) => array(ApolloClient.opaqueQueryObj); + jsExecutionResult('raw_t) => array(ApolloClient_Client.opaqueQueryObj); /* The type that the promise returned by the mutate function resolves to */ type executionResult('a) = { data: option('a), - errors: option(array(graphqlError)), + errors: option(array(Types.graphqlError)), }; type executionVariantResult('a) = | Data('a) - | Errors(array(graphqlError)) + | Errors(array(Types.graphqlError)) | NoData; }; @@ -35,7 +35,7 @@ type controlledResult('t) = { loading: bool, called: bool, data: option('t), - error: option(apolloError), + error: option(Types.apolloError), }; /* The type of the 'simple' result returned by the hook */ @@ -43,10 +43,10 @@ type controlledVariantResult('t) = | Loading | NotCalled | Data('t) - | Error(apolloError) + | Error(Types.apolloError) | NoData; -[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; +[@bs.module "graphql-tag"] external gql: Types.gql = "default"; type mutationResult('raw_t) = {. "data": option('raw_t)}; @@ -55,15 +55,15 @@ type options('raw_t, 'raw_t_variables) = { [@bs.optional] variables: 'raw_t_variables, [@bs.optional] - mutation: option(ReasonApolloTypes.queryString), + mutation: option(Types.queryString), [@bs.optional] - client: ApolloClient.t, + client: ApolloClient_Client.t, [@bs.optional] refetchQueries: Execution.refetchQueries('raw_t), [@bs.optional] awaitRefetchQueries: bool, [@bs.optional] - update: (ApolloClient.t, mutationResult('raw_t)) => unit, + update: (ApolloClient_Client.t, mutationResult('raw_t)) => unit, [@bs.optional] optimisticResponse: 'raw_t, }; @@ -75,7 +75,7 @@ type jsMutate('raw_t, 'raw_t_variables) = type mutation('t, 'raw_t, 'raw_t_variables) = ( ~variables: 'raw_t_variables=?, - ~client: ApolloClient.t=?, + ~client: ApolloClient_Client.t=?, ~refetchQueries: Execution.refetchQueries('raw_t)=?, ~awaitRefetchQueries: bool=?, ~optimisticResponse: 't=?, @@ -87,27 +87,27 @@ type mutation('t, 'raw_t, 'raw_t_variables) = [@bs.module "@apollo/client"] external useMutationJs: - (. ReasonApolloTypes.queryString, options('raw_t, 'raw_t_variables)) => + (. Types.queryString, options('raw_t, 'raw_t_variables)) => (jsMutate('raw_t, 'raw_t_variables), jsResult('raw_t)) = "useMutation"; exception Error(string); let useMutation: - ( - ~client: ApolloClient.t=?, - ~variables: 'raw_t_variables=?, - ~refetchQueries: Execution.refetchQueries('raw_t)=?, - ~awaitRefetchQueries: bool=?, - ~update: (ApolloClient.t, mutationResult('raw_t)) => unit=?, - ~optimisticResponse: 't=?, - ApolloHooksTypes.graphqlDefinition('t, 'raw_t) - ) => - ( - mutation('t, 'raw_t, 'raw_t_variables), - controlledVariantResult('t), - controlledResult('t), - ) = + type t raw_t raw_t_variables. + ( + ~client: ApolloClient_Client.t=?, + ~variables: raw_t_variables=?, + ~refetchQueries: Execution.refetchQueries(raw_t)=?, + ~awaitRefetchQueries: bool=?, + ~update: (ApolloClient_Client.t, mutationResult(raw_t)) => unit=?, + ~optimisticResponse: t=?, + (module Types.Operation with + type t = t and + type Raw.t = raw_t and + type Raw.t_variables = raw_t_variables) + ) => + (mutation(t, raw_t, raw_t_variables), controlledResult(t)) = ( ~client=?, ~variables=?, @@ -115,11 +115,11 @@ let useMutation: ~awaitRefetchQueries=?, ~update=?, ~optimisticResponse=?, - (parse, query, serialize), + (module Definition), ) => { let (jsMutate, jsResult) = useMutationJs(. - gql(. query), + gql(. Definition.query), options( ~client?, ~variables?, @@ -129,7 +129,7 @@ let useMutation: ~optimisticResponse=? switch (optimisticResponse) { | Some(optimisticResponse) => - Some(serialize(optimisticResponse)) + Some(Definition.serialize(optimisticResponse)) | None => None }, (), @@ -156,7 +156,7 @@ let useMutation: ~optimisticResponse=? switch (optimisticResponse) { | Some(optimisticResponse) => - Some(serialize(optimisticResponse)) + Some(Definition.serialize(optimisticResponse)) | None => None }, (), @@ -167,7 +167,7 @@ let useMutation: Execution.{ data: Js.Nullable.toOption(jsResult##data) - ->Belt.Option.map(parse), + ->Belt.Option.map(Definition.parse), errors: switch (Js.Nullable.toOption(jsResult##errors)) { | Some(errors) when Js.Array.length(errors) > 0 => @@ -176,12 +176,11 @@ let useMutation: }, }; - let simple = + let simple: Execution.executionVariantResult(Definition.t) = switch (full) { - | {errors: Some(errors)} => ( - Errors(errors): Execution.executionVariantResult('data) - ) + | {errors: Some(errors)} => Errors(errors) | {data: Some(data)} => Data(data) + | {errors: None, data: None} => NoData }; @@ -197,24 +196,90 @@ let useMutation: loading: jsResult##loading, called: jsResult##called, data: - jsResult##data->Js.Nullable.toOption->Belt.Option.map(parse), + jsResult##data + ->Js.Nullable.toOption + ->Belt.Option.map(Definition.parse), error: jsResult##error->Js.Nullable.toOption, }, [|jsResult|], ); + (mutate, full); + }; + +let useMutationLegacy: + type t raw_t raw_t_variables. + ( + ~client: ApolloClient_Client.t=?, + ~variables: raw_t_variables=?, + ~refetchQueries: Execution.refetchQueries(raw_t)=?, + ~awaitRefetchQueries: bool=?, + ~update: (ApolloClient_Client.t, mutationResult(raw_t)) => unit=?, + ~optimisticResponse: t=?, + (module Types.Operation with + type t = t and + type Raw.t = raw_t and + type Raw.t_variables = raw_t_variables) + ) => + ( + mutation(t, raw_t, raw_t_variables), + controlledVariantResult(t), + controlledResult(t), + ) = + ( + ~client=?, + ~variables=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~update=?, + ~optimisticResponse=?, + (module Definition), + ) => { + let (mutate, result) = + useMutation( + ~client?, + ~variables?, + ~refetchQueries?, + ~awaitRefetchQueries?, + ~update?, + ~optimisticResponse?, + (module Definition), + ); let simple = React.useMemo1( () => - switch (full) { + switch (result) { | {loading: true} => Loading | {error: Some(error)} => Error(error) | {data: Some(data)} => Data(data) | {called: false} => NotCalled | _ => NoData }, - [|full|], + [|result|], ); - (mutate, simple, full); + (mutate, simple, result); }; + +module Extend = (M: Types.Operation) => { + let use = + ( + ~client=?, + ~variables=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~update=?, + ~optimisticResponse=?, + (), + ) => { + useMutation( + ~client?, + ~variables?, + ~refetchQueries?, + ~awaitRefetchQueries?, + ~update?, + ~optimisticResponse?, + (module M), + ); + }; +}; diff --git a/src/ApolloHooksProvider.re b/src/ApolloClient_Provider.re similarity index 51% rename from src/ApolloHooksProvider.re rename to src/ApolloClient_Provider.re index 6341735..f98f4be 100644 --- a/src/ApolloHooksProvider.re +++ b/src/ApolloClient_Provider.re @@ -1,4 +1,4 @@ [@bs.module "@apollo/client"] [@react.component] external make: - (~client: ApolloClient.t, ~children: React.element) => React.element = + (~client: ApolloClient_Client.t, ~children: React.element) => React.element = "ApolloProvider"; diff --git a/src/ApolloClient_Query.re b/src/ApolloClient_Query.re new file mode 100644 index 0000000..e0e9173 --- /dev/null +++ b/src/ApolloClient_Query.re @@ -0,0 +1,329 @@ +module Types = ApolloClient_Types; + +type variant('a) = + | Data('a) + | Error(Types.apolloError) + | Loading + | NoData; + +/** + * https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/watchQueryOptions.ts#L139 + */ +type updateSubscriptionOptionsJs('raw_t, 'raw_t_variables) = { + . + "subscriptionData": {. "data": 'raw_t}, + "variables": Js.Nullable.t('raw_t_variables), +}; + +type updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables) = + ('raw_t, updateSubscriptionOptionsJs('raw_t, 'raw_t_variables)) => 'raw_t; + +[@bs.deriving abstract] +type subscribeToMoreOptionsJs('raw_t, 'raw_t_variables) = { + document: Types.queryString, + [@bs.optional] + variables: 'raw_t_variables, + [@bs.optional] + updateQuery: updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables), +}; + +type unsubscribeFnT = unit => unit; + +type updateQueryOptions('t, 'raw_t_variables) = { + fetchMoreResult: option('t), + variables: option('raw_t_variables), +}; + +module Raw = { + /** + * + * apollo-client/src/core/ObservableQuery.ts + */ + type updateQueryOptions('raw_t, 'raw_t_variables) = { + fetchMoreResult: Js.Nullable.t('raw_t), + variables: Js.Nullable.t('raw_t_variables), + }; + + /** + * apollo-client/src/core/watchQueryOptions.ts + */ + type fetchMoreOptions('raw_t, 'raw_t_variables) = { + variables: option('raw_t_variables), + updateQuery: + ('raw_t, updateQueryOptions('raw_t, 'raw_t_variables)) => 'raw_t, + }; +}; + +type queryResult('t, 'raw_t, 'raw_t_variables) = { + data: option('t), + loading: bool, + error: option(Types.apolloError), + networkStatus: Types.networkStatus, + refetch: (~variables: 'raw_t_variables=?, unit) => Js.Promise.t('t), + fetchMore: + ( + ~variables: 'raw_t_variables=?, + ~updateQuery: ('t, updateQueryOptions('t, 'raw_t_variables)) => 't, + unit + ) => + Js.Promise.t(unit), + rawFetchMore: + ( + ~variables: 'raw_t_variables=?, + ~updateQuery: ( + 'raw_t, + Raw.updateQueryOptions('raw_t, 'raw_t_variables) + ) => + 'raw_t, + unit + ) => + Js.Promise.t(unit), + startPolling: int => unit, + stopPolling: unit => unit, + subscribeToMore: + ( + ~document: Types.queryString, + ~variables: 'raw_t_variables=?, + ~updateQuery: updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables)=?, + unit + ) => + unsubscribeFnT, +}; + +[@bs.module "graphql-tag"] external gql: Types.gql = "default"; + +[@bs.deriving abstract] +type options('raw_t_variables) = { + [@bs.optional] + variables: 'raw_t_variables, + [@bs.optional] + client: ApolloClient_Client.t, + [@bs.optional] + notifyOnNetworkStatusChange: bool, + [@bs.optional] + fetchPolicy: string, + [@bs.optional] + errorPolicy: string, + [@bs.optional] + skip: bool, + [@bs.optional] + pollInterval: int, + [@bs.optional] + context: Types.Context.t, +}; + +type refetchResult('raw_t) = {data: Js.Nullable.t('raw_t)}; + +[@bs.module "@apollo/client"] +external useQueryJs: + (Types.queryString, options('raw_t_variables)) => + { + . + "data": Js.Nullable.t('raw_t), + "loading": bool, + "error": Js.Nullable.t(Types.apolloError), + [@bs.meth] + "refetch": + Js.Nullable.t('raw_t_variables) => Js.Promise.t(refetchResult('raw_t)), + [@bs.meth] + "fetchMore": + Raw.fetchMoreOptions('raw_t, 'raw_t_variables) => Js.Promise.t(unit), + "networkStatus": Js.Nullable.t(int), + [@bs.meth] "stopPolling": unit => unit, + [@bs.meth] "startPolling": int => unit, + [@bs.meth] + "subscribeToMore": + subscribeToMoreOptionsJs('raw_t, 'raw_t_variables) => unsubscribeFnT, + } = + "useQuery"; + +let useQuery: + type t t_variables raw_t raw_t_variables. + ( + ~client: ApolloClient_Client.t=?, + ~variables: raw_t_variables=?, + ~notifyOnNetworkStatusChange: bool=?, + ~fetchPolicy: Types.fetchPolicy=?, + ~errorPolicy: Types.errorPolicy=?, + ~skip: bool=?, + ~pollInterval: int=?, + ~context: Types.Context.t=?, + (module Types.Operation with + type t = t and + type Raw.t = raw_t and + type Raw.t_variables = raw_t_variables) + ) => + queryResult(t, raw_t, raw_t_variables) = + ( + ~client=?, + ~variables=?, + ~notifyOnNetworkStatusChange=?, + ~fetchPolicy=?, + ~errorPolicy=?, + ~skip=?, + ~pollInterval=?, + ~context=?, + (module Definition), + ) => { + let jsResult = + useQueryJs( + gql(. Definition.query), + options( + ~variables?, + ~client?, + ~notifyOnNetworkStatusChange?, + ~fetchPolicy=?fetchPolicy->Belt.Option.map(Types.fetchPolicyToJs), + ~errorPolicy=?errorPolicy->Belt.Option.map(Types.errorPolicyToJs), + ~skip?, + ~pollInterval?, + ~context?, + (), + ), + ); + + React.useMemo1( + () => + { + data: + jsResult##data + ->Js.Nullable.toOption + ->Belt.Option.flatMap(data => + switch (Definition.parse(data)) { + | parsedData => Some(parsedData) + | exception _ => None + } + ), + loading: jsResult##loading, + error: jsResult##error->Js.Nullable.toOption, + networkStatus: + ApolloClient_Types.toNetworkStatus(jsResult##networkStatus), + refetch: (~variables=?, ()) => + jsResult##refetch(Js.Nullable.fromOption(variables)) + |> Js.Promise.then_(result => + Definition.parse( + result.data->Js.Nullable.toOption->Belt.Option.getExn, + ) + |> Js.Promise.resolve + ), + rawFetchMore: (~variables=?, ~updateQuery, ()) => + jsResult##fetchMore({Raw.variables, Raw.updateQuery}), + fetchMore: (~variables=?, ~updateQuery, ()) => { + jsResult##fetchMore({ + Raw.variables, + Raw.updateQuery: + (previousResult, {fetchMoreResult, variables}) => { + let result = + updateQuery( + Definition.parse(previousResult), + { + fetchMoreResult: + switch (Js.Nullable.toOption(fetchMoreResult)) { + | None => None + | Some(fetchMoreResult) => + Some(Definition.parse(fetchMoreResult)) + }, + variables: Js.Nullable.toOption(variables), + }, + ); + Definition.serialize(result); + }, + }); + }, + stopPolling: () => jsResult##stopPolling(), + startPolling: interval => jsResult##startPolling(interval), + subscribeToMore: (~document, ~variables=?, ~updateQuery=?, ()) => + jsResult##subscribeToMore( + subscribeToMoreOptionsJs( + ~document, + ~variables?, + ~updateQuery?, + (), + ), + ), + }, + [|jsResult|], + ); + }; + +let useQueryLegacy: + type t t_variables raw_t raw_t_variables. + ( + ~client: ApolloClient_Client.t=?, + ~variables: raw_t_variables=?, + ~notifyOnNetworkStatusChange: bool=?, + ~fetchPolicy: Types.fetchPolicy=?, + ~errorPolicy: Types.errorPolicy=?, + ~skip: bool=?, + ~pollInterval: int=?, + ~context: Types.Context.t=?, + (module Types.Operation with + type t = t and + type Raw.t = raw_t and + type Raw.t_variables = raw_t_variables) + ) => + (variant(t), queryResult(t, raw_t, raw_t_variables)) = + ( + ~client=?, + ~variables=?, + ~notifyOnNetworkStatusChange=?, + ~fetchPolicy=?, + ~errorPolicy=?, + ~skip=?, + ~pollInterval=?, + ~context=?, + (module Definition), + ) => { + let result = + useQuery( + ~client?, + ~variables?, + ~notifyOnNetworkStatusChange?, + ~fetchPolicy?, + ~errorPolicy?, + ~skip?, + ~pollInterval?, + ~context?, + (module Definition), + ); + + let simple = + React.useMemo1( + () => + switch (result) { + | {loading: true} => Loading + | {error: Some(error)} => Error(error) + | {data: Some(data)} => Data(data) + | _ => NoData + }, + [|result|], + ); + + (simple, result); + }; + +module Extend = (M: Types.Operation) => { + let use = + ( + ~client=?, + ~variables=?, + ~notifyOnNetworkStatusChange=?, + ~fetchPolicy=?, + ~errorPolicy=?, + ~skip=?, + ~pollInterval=?, + ~context=?, + (), + ) => { + useQuery( + ~client?, + ~variables?, + ~notifyOnNetworkStatusChange?, + ~fetchPolicy?, + ~errorPolicy?, + ~skip?, + ~pollInterval?, + ~context?, + (module M), + ); + }; +}; diff --git a/src/ApolloHooksSubscription.re b/src/ApolloClient_Subscription.re similarity index 82% rename from src/ApolloHooksSubscription.re rename to src/ApolloClient_Subscription.re index 7d7c3ad..7578fdc 100644 --- a/src/ApolloHooksSubscription.re +++ b/src/ApolloClient_Subscription.re @@ -1,4 +1,5 @@ -open ApolloHooksTypes; +module Types = ApolloClient_Types; + type error = {. "message": string}; type variant('a) = @@ -13,7 +14,7 @@ type result('a) = { error: option(error), }; -[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; +[@bs.module "graphql-tag"] external gql: Types.gql = "default"; [@bs.deriving abstract] type options('raw_t, 'raw_t_variables) = { @@ -24,12 +25,12 @@ type options('raw_t, 'raw_t_variables) = { [@bs.optional] onSubscriptionData: unit => unit, [@bs.optional] - client: ApolloClient.t, + client: ApolloClient_Client.t, }; [@bs.module "@apollo/client"] external useSubscription: - (ReasonApolloTypes.queryString, options('raw_t, 'raw_t_variables)) => + (Types.queryString, options('raw_t, 'raw_t_variables)) => { . "data": Js.Nullable.t(Js.Json.t), @@ -41,9 +42,9 @@ external useSubscription: let useSubscription: ( ~variables: Js.Json.t=?, - ~client: ApolloClient.t=?, + ~client: ApolloClient_Client.t=?, ~skip: bool=?, - ApolloHooksTypes.graphqlDefinition('t, 'raw_t) + Types.graphqlDefinition('t, 'raw_t) ) => (variant('t), result('t)) = (~variables=?, ~client=?, ~skip=?, (parse, query, _)) => { diff --git a/src/ApolloHooksTypes.re b/src/ApolloClient_Types.re similarity index 53% rename from src/ApolloHooksTypes.re rename to src/ApolloClient_Types.re index 1bac2ba..2d41f37 100644 --- a/src/ApolloHooksTypes.re +++ b/src/ApolloClient_Types.re @@ -1,3 +1,60 @@ +/** + * An abstract type to describe a query string object. + */ +type queryString; + +/** + * The signature of the `graphql-tag/gql` function that transforms a GraphQL + * query string to the standard GraphQL AST. + * https://github.com/apollographql/graphql-tag + */ +type gql = (. string) => queryString; + +/** + * An abstract type to describe an Apollo Link object. + */ +type apolloLink; + +/** + * An abstract type to describe an Apollo Cache object. + */ +type apolloCache; + +type apolloErrorExtensions = {code: Js.Nullable.t(string)}; + +type graphqlError = { + message: string, + name: Js.Nullable.t(string), + extensions: Js.Nullable.t(apolloErrorExtensions), + locations: Js.Nullable.t(array(string)), + path: Js.Nullable.t(array(string)), + nodes: Js.Nullable.t(array(string)), +}; + +type executionResult('raw_t) = { + errors: Js.Nullable.t(Js.Array.t(graphqlError)), + data: Js.Nullable.t('raw_t), +}; + +module type Definition = { + let query: string; + + module Raw: { + type t; + type t_variables; + }; + type t; + + let parse: Raw.t => t; + let serialize: t => Raw.t; +}; + +type apolloError = { + message: string, + graphQLErrors: Js.Nullable.t(array(graphqlError)), + networkError: Js.Nullable.t(string), +}; + /** * apollo-client/src/core/networkStatus */ @@ -61,28 +118,6 @@ let errorPolicyToJs = errorPolicy => | All => "all" }; -/** - * apollo-client/src/errors/ApolloError.ts - */ -type apolloErrorExtensions = {. "code": Js.Nullable.t(string)}; - -type graphqlError = { - . - "message": string, - "name": Js.Nullable.t(string), - "extensions": Js.Nullable.t(apolloErrorExtensions), - "locations": Js.Nullable.t(array(string)), - "path": Js.Nullable.t(array(string)), - "nodes": Js.Nullable.t(array(string)), -}; - -type apolloError = { - . - "message": string, - "graphQLErrors": Js.Nullable.t(array(graphqlError)), - "networkError": Js.Nullable.t(string), -}; - type parse('raw_t, 't) = 'raw_t => 't; type serialize('t, 'raw_t) = 't => 'raw_t; type query = string; @@ -97,3 +132,16 @@ module Context = { type t = Js.Dict.t(string); let make = (context): t => Js.Dict.fromList(context); }; + +module type Operation = { + let query: string; + + module Raw: { + type t; + type t_variables; + }; + type t; + + let parse: Raw.t => t; + let serialize: t => Raw.t; +}; diff --git a/src/ApolloHooks.re b/src/ApolloHooks.re deleted file mode 100644 index 508b416..0000000 --- a/src/ApolloHooks.re +++ /dev/null @@ -1,173 +0,0 @@ -module Mutation = ApolloHooksMutation; -module Query = ApolloHooksQuery; -module Provider = ApolloHooksProvider; -module Subscription = ApolloHooksSubscription; - -/** - This is probably the one hook you'll use the most. A quick demo: - - {[ - open ApolloHooks; - - module Query = [%graphql {| - query MyQuery { - me { id, name } - } - |}]; - - [@react.component] - let make = () => { - /* In Reason we prefix variables that we are not going to use with _ */ - let (simple, _full) = useQuery(Query.definitions); - - /* When using simple with Reason's pattern-matching operator, the compiler will force you to cover every single branch of the variant type */ - switch(simple) { - | Loading => React.string("loading...") - | Error(error) => - Js.log(error); - React.string("Something went wrong!") - | Data(data) => - React.string("Hello, " ++ data##me##name) - /* Every. Single. One. Of Them. */ - | NoData => - React.string("Woa something went really wrong! Glady we use Reason and it forced us to handle this! Report this issue") - } - } - ]} - - Why we return a tuple? While designing and using the API we came to the conclusion that would be much more convient to have a value that would attend - the majority of simple usages and a full for when you need to do a complex UI, such as infinite scroll. - - The value [simple] ({!type:Query.variant('a)}) helps you to consume your data with simplicity, type safety and exhaustiveness check. - But for those cases where you really want do do a fine-grained control of your data flow – such as when you have [loading] and [data] at the same time – - that's when [full] ({!type:Query.queryResult('a)}) becomes more useful. - - {[ - module Query = [%graphql {| - query MyQuery { - me { id, name } - } - |}]; - - [@react.component] - let make = () => { - let (_simple, full) = useQuery(Query.definitions); - - /* `full` is a record type so you pattern against it's possible combos of values */ - switch(full) { - /* Initial loading */ - | { loading: true, data: None } => React.string("loading...") - /* Error but no data */ - | { loading: false, data: None, error: Some(error) } => React.string("Something went wrong") - /* When we have some data and we tried to refetch but got an error */ - | { loading: false, data: Some(data), error: Some(error) } => - <> - {React.string("Something went wrong")} - - - /* Just data */ - | { loading: false, data: Some(data), error: None } => - <> - {React.string("Something went wrong")} - - - | Data(data) => - React.string("Hello, " ++ data##me##name) - /* Not loading? No data? No error? That's weird */ - | {loading: false, data: None, error: null} => - React.string("Woa something went really wrong! But the programmer remembered to handle this case! Report to us") - } - } - ]} - - Quite more complex right? Gladly it's not always that we have that level of complexity. - - That covers the most common cases of usage. If you want to see more complex usages check out the examples folder. - */ -let useQuery = Query.useQuery; - -/** - Second most used! Here's a quick demo: - - {[ - open ApolloHooks; - - module Mutation = [%graphql {| - mutation MyMutation($input: MyMutationInput!) { - myMutation(input: $input) { error } - } - |}]; - - [@react.component] - let make = () => { - /* `simple` and `full` follow the same principle of `useQuery`. */ - let (mutate, simple, _full) = useMutation(Mutation.definitions); - - /* When using simple with Reason's pattern-matching operator, the compiler will force you to cover every single branch of the variant type */ - switch(simple) { - | Loading => React.string("loading...") - | Error(error) => - Js.log(error); - React.string("Something went wrong!") - | Data(data) => -
- {React.string("Hello, " ++ data##me##name)} -
- /* Every. Single. One. Of Them. */ - | NotCalled => - } - ]} - */ -let useMutation = Mutation.useMutation; - -let toReadQueryOptions = result => { - "query": ApolloClient.gql(. result##query), - "variables": Js.Nullable.fromOption(Some(result##variables)), -}; - -/** useSubscription bindings */ -let useSubscription = Subscription.useSubscription; - -/** Helper to generate the shape of a query for [refetchQueries] mutation param. Take a look in examples/persons/src/EditPerson.re for a more complete demo of usage. */ -let toQueryObj: - (string, 'raw_t_variables) => ApolloClient.queryObj('raw_t_variables) = - (theQuery, variables) => - ApolloClient.{query: ApolloClient.gql(. theQuery), variables}; - -let toOpaqueQueryObj: (string, 'raw_t_variables) => ApolloClient.opaqueQueryObj = - (theQuery, variables) => - ApolloClient.toOpaqueQueryObj( - ApolloClient.{query: ApolloClient.gql(. theQuery), variables}, - ); diff --git a/src/ApolloHooksClient.re b/src/ApolloHooksClient.re deleted file mode 100644 index 77c90c6..0000000 --- a/src/ApolloHooksClient.re +++ /dev/null @@ -1,54 +0,0 @@ -open ApolloHooksTypes; - -type queryError = {. "message": string}; -type queryResult('a) = { - data: option('a), - errors: option(array(queryError)), - loading: bool, - networkStatus: ApolloHooksTypes.networkStatus, - stale: bool, -}; - -[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; - -type options('data); -[@bs.obj] -external doMakeOptions: - ( - ~query: ReasonApolloTypes.queryString, - ~variables: 'raw_t_variables=?, - ~notifyOnNetworkStatusChange: bool=?, - ~fetchPolicy: string=?, - ~errorPolicy: string=?, - ~pollInterval: int=?, - unit - ) => - options('data); - -let makeOptions = - ( - ~variables: 'raw_t_variables=?, - ~notifyOnNetworkStatusChange=?, - ~fetchPolicy=?, - ~errorPolicy=?, - ~pollInterval=?, - (_, query, _): graphqlDefinition('data, _), - ) => { - doMakeOptions( - ~query=gql(. query), - ~variables?, - ~notifyOnNetworkStatusChange?, - ~fetchPolicy=?fetchPolicy->Belt.Option.map(f => fetchPolicyToJs(f)), - ~errorPolicy=?errorPolicy->Belt.Option.map(e => errorPolicyToJs(e)), - ~pollInterval?, - (), - ); -}; - -[@bs.send] -external query: - (ApolloClient.t, options('data)) => Js.Promise.t(queryResult('data)) = - "query"; - -[@bs.module "../../../apolloClient"] -external client: ApolloClient.t = "default"; diff --git a/src/ApolloHooksQuery.re b/src/ApolloHooksQuery.re deleted file mode 100644 index 42f0f08..0000000 --- a/src/ApolloHooksQuery.re +++ /dev/null @@ -1,259 +0,0 @@ -open ApolloHooksTypes; - -type variant('a) = - | Data('a) - | Error(apolloError) - | Loading - | NoData; - -/** - * https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/watchQueryOptions.ts#L139 - */ -type updateSubscriptionOptionsJs('raw_t, 'raw_t_variables) = { - . - "subscriptionData": {. "data": 'raw_t}, - "variables": Js.Nullable.t('raw_t_variables), -}; - -type updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables) = - ('raw_t, updateSubscriptionOptionsJs('raw_t, 'raw_t_variables)) => 'raw_t; - -[@bs.deriving abstract] -type subscribeToMoreOptionsJs('raw_t, 'raw_t_variables) = { - document: ReasonApolloTypes.queryString, - [@bs.optional] - variables: 'raw_t_variables, - [@bs.optional] - updateQuery: updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables), -}; - -type unsubscribeFnT = unit => unit; - -type updateQueryOptions('t, 'raw_t_variables) = { - fetchMoreResult: option('t), - variables: option('raw_t_variables), -}; - -module Raw = { - /** - * - * apollo-client/src/core/ObservableQuery.ts - */ - type updateQueryOptions('raw_t, 'raw_t_variables) = { - fetchMoreResult: Js.Nullable.t('raw_t), - variables: Js.Nullable.t('raw_t_variables), - }; - - /** - * apollo-client/src/core/watchQueryOptions.ts - */ - type fetchMoreOptions('raw_t, 'raw_t_variables) = { - variables: option('raw_t_variables), - updateQuery: - ('raw_t, updateQueryOptions('raw_t, 'raw_t_variables)) => 'raw_t, - }; -}; - -type queryResult('t, 'raw_t, 'raw_t_variables) = { - data: option('t), - loading: bool, - error: option(apolloError), - networkStatus: ApolloHooksTypes.networkStatus, - refetch: (~variables: 'raw_t_variables=?, unit) => Js.Promise.t('t), - fetchMore: - ( - ~variables: 'raw_t_variables=?, - ~updateQuery: ('t, updateQueryOptions('t, 'raw_t_variables)) => 't, - unit - ) => - Js.Promise.t(unit), - rawFetchMore: - ( - ~variables: 'raw_t_variables=?, - ~updateQuery: ( - 'raw_t, - Raw.updateQueryOptions('raw_t, 'raw_t_variables) - ) => - 'raw_t, - unit - ) => - Js.Promise.t(unit), - startPolling: int => unit, - stopPolling: unit => unit, - subscribeToMore: - ( - ~document: ReasonApolloTypes.queryString, - ~variables: 'raw_t_variables=?, - ~updateQuery: updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables)=?, - unit - ) => - unsubscribeFnT, -}; - -[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; - -[@bs.deriving abstract] -type options('raw_t_variables) = { - [@bs.optional] - variables: 'raw_t_variables, - [@bs.optional] - client: ApolloClient.t, - [@bs.optional] - notifyOnNetworkStatusChange: bool, - [@bs.optional] - fetchPolicy: string, - [@bs.optional] - errorPolicy: string, - [@bs.optional] - skip: bool, - [@bs.optional] - pollInterval: int, - [@bs.optional] - context: Context.t, -}; - -type refetchResult('raw_t) = {data: Js.Nullable.t('raw_t)}; - -[@bs.module "@apollo/client"] -external useQueryJs: - (ReasonApolloTypes.queryString, options('raw_t_variables)) => - { - . - "data": Js.Nullable.t('raw_t), - "loading": bool, - "error": Js.Nullable.t(apolloError), - [@bs.meth] - "refetch": - Js.Nullable.t('raw_t_variables) => Js.Promise.t(refetchResult('raw_t)), - [@bs.meth] - "fetchMore": - Raw.fetchMoreOptions('raw_t, 'raw_t_variables) => Js.Promise.t(unit), - "networkStatus": Js.Nullable.t(int), - [@bs.meth] "stopPolling": unit => unit, - [@bs.meth] "startPolling": int => unit, - [@bs.meth] - "subscribeToMore": - subscribeToMoreOptionsJs('raw_t, 'raw_t_variables) => unsubscribeFnT, - } = - "useQuery"; - -let useQuery: - ( - ~client: ApolloClient.t=?, - ~variables: 'raw_t_variables=?, - ~notifyOnNetworkStatusChange: bool=?, - ~fetchPolicy: ApolloHooksTypes.fetchPolicy=?, - ~errorPolicy: ApolloHooksTypes.errorPolicy=?, - ~skip: bool=?, - ~pollInterval: int=?, - ~context: Context.t=?, - graphqlDefinition('t, 'raw_t) - ) => - (variant('t), queryResult('t, 'raw_t, 'raw_t_variables)) = - ( - ~client=?, - ~variables=?, - ~notifyOnNetworkStatusChange=?, - ~fetchPolicy=?, - ~errorPolicy=?, - ~skip=?, - ~pollInterval=?, - ~context=?, - (parse, query, serialize), - ) => { - let jsResult = - useQueryJs( - gql(. query), - options( - ~variables?, - ~client?, - ~notifyOnNetworkStatusChange?, - ~fetchPolicy=? - fetchPolicy->Belt.Option.map(ApolloHooksTypes.fetchPolicyToJs), - ~errorPolicy=? - errorPolicy->Belt.Option.map(ApolloHooksTypes.errorPolicyToJs), - ~skip?, - ~pollInterval?, - ~context?, - (), - ), - ); - - let result = - React.useMemo1( - () => - { - data: - jsResult##data - ->Js.Nullable.toOption - ->Belt.Option.flatMap(data => - switch (parse(data)) { - | parsedData => Some(parsedData) - | exception _ => None - } - ), - loading: jsResult##loading, - error: jsResult##error->Js.Nullable.toOption, - networkStatus: - ApolloHooksTypes.toNetworkStatus(jsResult##networkStatus), - refetch: (~variables=?, ()) => - jsResult##refetch(Js.Nullable.fromOption(variables)) - |> Js.Promise.then_(result => - parse( - result.data->Js.Nullable.toOption->Belt.Option.getExn, - ) - |> Js.Promise.resolve - ), - rawFetchMore: (~variables=?, ~updateQuery, ()) => - jsResult##fetchMore({Raw.variables, Raw.updateQuery}), - fetchMore: (~variables=?, ~updateQuery, ()) => { - jsResult##fetchMore({ - Raw.variables, - Raw.updateQuery: - (previousResult, {fetchMoreResult, variables}) => { - let result = - updateQuery( - parse(previousResult), - { - fetchMoreResult: - switch (Js.Nullable.toOption(fetchMoreResult)) { - | None => None - | Some(fetchMoreResult) => - Some(parse(fetchMoreResult)) - }, - variables: Js.Nullable.toOption(variables), - }, - ); - serialize(result); - }, - }); - }, - stopPolling: () => jsResult##stopPolling(), - startPolling: interval => jsResult##startPolling(interval), - subscribeToMore: (~document, ~variables=?, ~updateQuery=?, ()) => - jsResult##subscribeToMore( - subscribeToMoreOptionsJs( - ~document, - ~variables?, - ~updateQuery?, - (), - ), - ), - }, - [|jsResult|], - ); - - let simple = - React.useMemo1( - () => - switch (result) { - | {loading: true} => Loading - | {error: Some(error)} => Error(error) - | {data: Some(data)} => Data(data) - | _ => NoData - }, - [|result|], - ); - - (simple, result); - }; diff --git a/src/ReasonApolloTypes.re b/src/ReasonApolloTypes.re deleted file mode 100644 index f160412..0000000 --- a/src/ReasonApolloTypes.re +++ /dev/null @@ -1,55 +0,0 @@ -/** - * An abstract type to describe a query string object. - */ -type queryString; - -/** - * The signature of the `graphql-tag/gql` function that transforms a GraphQL - * query string to the standard GraphQL AST. - * https://github.com/apollographql/graphql-tag - */ -type gql = (. string) => queryString; - -/** - * An abstract type to describe an Apollo Link object. - */ -type apolloLink; - -/** - * An abstract type to describe an Apollo Cache object. - */ -type apolloCache; - -type apolloErrorExtensions = {code: Js.Nullable.t(string)}; - -type graphqlError = { - message: string, - name: Js.Nullable.t(string), - extensions: Js.Nullable.t(apolloErrorExtensions), - locations: Js.Nullable.t(array(string)), - path: Js.Nullable.t(array(string)), - nodes: Js.Nullable.t(array(string)), -}; - -type executionResult('raw_t) = { - errors: Js.Nullable.t(Js.Array.t(graphqlError)), - data: Js.Nullable.t('raw_t), -}; - -module type Config = { - let query: string; - module Raw: { - type t; - type t_variables; - }; - type t; - type t_variables; - - let parse: Raw.t => t; -}; - -type apolloError = { - message: string, - graphQLErrors: Js.Nullable.t(array(graphqlError)), - networkError: Js.Nullable.t(string), -}; diff --git a/src/index.mld b/src/index.mld index 91bbb42..4d0de83 100644 --- a/src/index.mld +++ b/src/index.mld @@ -2,4 +2,4 @@ Hello! -Check out the module {!module:ApolloHooks} to get started. +Check out the module {!module:ApolloClient} to get started. From 05bb4da2073ae909c030b252d0b014c8963e5dd8 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Sat, 23 May 2020 15:43:10 +0800 Subject: [PATCH 07/13] Fix type --- src/ApolloClient_Subscription.re | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ApolloClient_Subscription.re b/src/ApolloClient_Subscription.re index 7578fdc..467b3cd 100644 --- a/src/ApolloClient_Subscription.re +++ b/src/ApolloClient_Subscription.re @@ -33,7 +33,7 @@ external useSubscription: (Types.queryString, options('raw_t, 'raw_t_variables)) => { . - "data": Js.Nullable.t(Js.Json.t), + "data": Js.Nullable.t('raw_t), "loading": bool, "error": Js.Nullable.t(error), } = From 8ec92ac4c225ed3abc0f434ff0286442a3dc1b18 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 2 Jun 2020 09:28:18 +0800 Subject: [PATCH 08/13] Add more functionality --- src/ApolloClient.re | 3 + src/ApolloClient_ApolloLink.re | 126 ++++++++++++++++++++++++++++++ src/ApolloClient_Consumer.re | 10 +++ src/ApolloClient_InMemoryCache.re | 41 ++++++++++ src/ApolloClient_Mutation.re | 18 ++--- src/ApolloClient_Query.re | 18 ++--- src/ApolloClient_Subscription.re | 52 ++++++------ src/ApolloClient_Types.re | 81 +++++++++++++++---- 8 files changed, 292 insertions(+), 57 deletions(-) create mode 100644 src/ApolloClient_ApolloLink.re create mode 100644 src/ApolloClient_Consumer.re create mode 100644 src/ApolloClient_InMemoryCache.re diff --git a/src/ApolloClient.re b/src/ApolloClient.re index 6ba36a8..4c19c9f 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -174,3 +174,6 @@ let toOpaqueQueryObj: (string, 'raw_t_variables) => Client.opaqueQueryObj = Client.toOpaqueQueryObj( Client.{query: Client.gql(. theQuery), variables}, ); + +[@bs.module "@apollo/client"] +external useApolloClient: unit => ApolloClient_Client.t = "useApolloClient"; diff --git a/src/ApolloClient_ApolloLink.re b/src/ApolloClient_ApolloLink.re new file mode 100644 index 0000000..b125a7b --- /dev/null +++ b/src/ApolloClient_ApolloLink.re @@ -0,0 +1,126 @@ +module Types = ApolloClient_Types; + +type fetch; +type request; +type context; + +type linkOptions = { + uri: string, + includeExtensions: Js.Nullable.t(bool), + fetch: Js.Nullable.t(fetch), + headers: Js.Nullable.t(Js.Json.t), + credentials: Js.Nullable.t(string), + fetchOptions: Js.Nullable.t(Js.Json.t), +}; + +type fetchResult('raw_t) = { + errors: Js.Nullable.t(Js.Array.t(Types.graphqlError)), + data: Js.Nullable.t('raw_t), + extensions: Js.Json.t, + context: Js.Json.t, +}; + +type nextLink('raw_t, 'raw_t_variables) = + Types.operation('raw_t_variables) => + Types.Observable.t(fetchResult('raw_t)); + +type makeCb('raw_t, 'raw_t_variables) = + (Types.operation('raw_t_variables), nextLink('raw_t, 'raw_t_variables)) => + Types.Observable.t(fetchResult('raw_t)); +external make: makeCb('raw_t, 'raw_t_variables) => Types.apolloLink; + +/* Bind the method `from`, used to compose links together */ +[@bs.module "@apollo/client"] +external from: array(Types.apolloLink) => Types.apolloLink = "from"; + +/* Bind the method split. Based on a test send left or right */ +[@bs.module "@apollo/client"] +external split: + (Types.splitTest => bool, Types.apolloLink, Types.apolloLink) => + Types.apolloLink = + "split"; + +module HttpLink = { + [@bs.module "@apollo/client"] [@bs.new] + external jsMake: linkOptions => Types.apolloLink = "HttpLink"; + let createHttpLink = + ( + ~uri, + ~includeExtensions=?, + ~fetch=?, + ~headers=?, + ~credentials=?, + ~fetchOptions=?, + (), + ) => { + jsMake({ + uri, + includeExtensions: Js.Nullable.fromOption(includeExtensions), + fetch: Js.Nullable.fromOption(fetch), + headers: Js.Nullable.fromOption(headers), + credentials: Js.Nullable.fromOption(credentials), + fetchOptions: Js.Nullable.fromOption(fetchOptions), + }); + }; +}; + +module LinkContext = { + /* Bind the setContext method */ + [@bs.module "@apollo/link-context"] + external setContext: + ([@bs.uncurry] ((request, context) => Js.Json.t)) => Types.apolloLink = + "setContext"; + + external setContextPromise: + ((request, context) => Js.Promise.t(Js.Json.t)) => Types.apolloLink = + "setContext"; +}; + +module LinkError = { + /* Bind the onError method */ + [@bs.module "@apollo/link-error"] + external onError: + (Types.errorResponse('raw_t, 'raw_t_variables) => unit) => + Types.apolloLink = + "onError"; +}; + +/* bind apollo-link-ws */ +[@bs.module "@apollo/link-ws"] [@bs.new] +external webSocketLink: Types.webSocketLink => Types.apolloLink = + "WebSocketLink"; + +module UploadLink = { + type uploadLinkOptions = { + uri: Js.Nullable.t(string), + fetch: Js.Nullable.t(fetch), + fetchOptions: Js.Nullable.t(Js.t({.})), + credentials: Js.Nullable.t(string), + headers: Js.Nullable.t(Js.Json.t), + includeExtensions: Js.Nullable.t(bool), + }; + + /* Bind createUploadLink function from apollo upload link */ + [@bs.module "apollo-upload-client"] + external jsMake: uploadLinkOptions => Types.apolloLink = "createUploadLink"; + let make = + ( + ~uri=?, + ~fetch=?, + ~fetchOptions=?, + ~credentials=?, + ~headers=?, + ~includeExtensions=?, + (), + ) => + jsMake( + Js.Nullable.{ + uri: fromOption(uri), + fetch: fromOption(fetch), + fetchOptions: fromOption(fetchOptions), + credentials: fromOption(credentials), + headers: fromOption(headers), + includeExtensions: fromOption(includeExtensions), + }, + ); +}; diff --git a/src/ApolloClient_Consumer.re b/src/ApolloClient_Consumer.re new file mode 100644 index 0000000..33792d2 --- /dev/null +++ b/src/ApolloClient_Consumer.re @@ -0,0 +1,10 @@ +module JsConsumer = { + [@bs.module "react-apollo"] [@react.component] + external make: + (~children: ApolloClient_Client.t => React.element) => React.element = + "ApolloConsumer"; +}; + +[@react.component] +let make = (~children: ApolloClient_Client.t => React.element) => + {client => children(client)} ; diff --git a/src/ApolloClient_InMemoryCache.re b/src/ApolloClient_InMemoryCache.re new file mode 100644 index 0000000..b447396 --- /dev/null +++ b/src/ApolloClient_InMemoryCache.re @@ -0,0 +1,41 @@ +module Types = ApolloClient_Types; + +/** + * Used on the client to rehydrate the cache using the initial data passed from the server + * - e.g. window.__APOLLO_STATE__ + */ +type restoreData; + +/** + * Define the data to pass to the restore method that'll be used used to rehydrate client. + * If you don't want to pass any data, simply return `Js_null_undefined.undefined`. + */ +type inMemoryCacheRestoreData = Js.Nullable.t(restoreData); + +/** + * CreateInMemoryCache + * https://github.com/apollographql/apollo-client/tree/master/packages/apollo-cache-inmemory + */ +/* Bind the InMemoryCache class */ +[@bs.module "@apollo/client"] [@bs.new] +external apolloInMemoryCache: 'a => Types.apolloCache = "InMemoryCache"; + +/* Bind the restore method */ +[@bs.send.pipe: 't] +external restore: inMemoryCacheRestoreData => Types.apolloCache = "restore"; + +/* Instantiate a new cache object */ +[@bs.obj] +external makeApolloInMemoryCacheParams: + ( + ~possibleTypes: Js.Dict.t(array(string))=?, + ~dataIdFromObject: Js.t({..}) => string=? + ) => + _; + +let createInMemoryCache = (~dataIdFromObject=?, ~possibleTypes=?, ()) => { + /* Apollo Client, looks for key in Object. Doesn't check if value is null */ + apolloInMemoryCache( + makeApolloInMemoryCacheParams(~dataIdFromObject?, ~possibleTypes?), + ); +}; diff --git a/src/ApolloClient_Mutation.re b/src/ApolloClient_Mutation.re index 2933041..71fa6f2 100644 --- a/src/ApolloClient_Mutation.re +++ b/src/ApolloClient_Mutation.re @@ -115,11 +115,11 @@ let useMutation: ~awaitRefetchQueries=?, ~update=?, ~optimisticResponse=?, - (module Definition), + (module Operation), ) => { let (jsMutate, jsResult) = useMutationJs(. - gql(. Definition.query), + gql(. Operation.query), options( ~client?, ~variables?, @@ -129,7 +129,7 @@ let useMutation: ~optimisticResponse=? switch (optimisticResponse) { | Some(optimisticResponse) => - Some(Definition.serialize(optimisticResponse)) + Some(Operation.serialize(optimisticResponse)) | None => None }, (), @@ -156,7 +156,7 @@ let useMutation: ~optimisticResponse=? switch (optimisticResponse) { | Some(optimisticResponse) => - Some(Definition.serialize(optimisticResponse)) + Some(Operation.serialize(optimisticResponse)) | None => None }, (), @@ -167,7 +167,7 @@ let useMutation: Execution.{ data: Js.Nullable.toOption(jsResult##data) - ->Belt.Option.map(Definition.parse), + ->Belt.Option.map(Operation.parse), errors: switch (Js.Nullable.toOption(jsResult##errors)) { | Some(errors) when Js.Array.length(errors) > 0 => @@ -176,7 +176,7 @@ let useMutation: }, }; - let simple: Execution.executionVariantResult(Definition.t) = + let simple: Execution.executionVariantResult(Operation.t) = switch (full) { | {errors: Some(errors)} => Errors(errors) | {data: Some(data)} => Data(data) @@ -198,7 +198,7 @@ let useMutation: data: jsResult##data ->Js.Nullable.toOption - ->Belt.Option.map(Definition.parse), + ->Belt.Option.map(Operation.parse), error: jsResult##error->Js.Nullable.toOption, }, [|jsResult|], @@ -233,7 +233,7 @@ let useMutationLegacy: ~awaitRefetchQueries=?, ~update=?, ~optimisticResponse=?, - (module Definition), + (module Operation), ) => { let (mutate, result) = useMutation( @@ -243,7 +243,7 @@ let useMutationLegacy: ~awaitRefetchQueries?, ~update?, ~optimisticResponse?, - (module Definition), + (module Operation), ); let simple = React.useMemo1( diff --git a/src/ApolloClient_Query.re b/src/ApolloClient_Query.re index e0e9173..b15fd85 100644 --- a/src/ApolloClient_Query.re +++ b/src/ApolloClient_Query.re @@ -163,11 +163,11 @@ let useQuery: ~skip=?, ~pollInterval=?, ~context=?, - (module Definition), + (module Operation), ) => { let jsResult = useQueryJs( - gql(. Definition.query), + gql(. Operation.query), options( ~variables?, ~client?, @@ -188,7 +188,7 @@ let useQuery: jsResult##data ->Js.Nullable.toOption ->Belt.Option.flatMap(data => - switch (Definition.parse(data)) { + switch (Operation.parse(data)) { | parsedData => Some(parsedData) | exception _ => None } @@ -200,7 +200,7 @@ let useQuery: refetch: (~variables=?, ()) => jsResult##refetch(Js.Nullable.fromOption(variables)) |> Js.Promise.then_(result => - Definition.parse( + Operation.parse( result.data->Js.Nullable.toOption->Belt.Option.getExn, ) |> Js.Promise.resolve @@ -214,18 +214,18 @@ let useQuery: (previousResult, {fetchMoreResult, variables}) => { let result = updateQuery( - Definition.parse(previousResult), + Operation.parse(previousResult), { fetchMoreResult: switch (Js.Nullable.toOption(fetchMoreResult)) { | None => None | Some(fetchMoreResult) => - Some(Definition.parse(fetchMoreResult)) + Some(Operation.parse(fetchMoreResult)) }, variables: Js.Nullable.toOption(variables), }, ); - Definition.serialize(result); + Operation.serialize(result); }, }); }, @@ -271,7 +271,7 @@ let useQueryLegacy: ~skip=?, ~pollInterval=?, ~context=?, - (module Definition), + (module Operation), ) => { let result = useQuery( @@ -283,7 +283,7 @@ let useQueryLegacy: ~skip?, ~pollInterval?, ~context?, - (module Definition), + (module Operation), ); let simple = diff --git a/src/ApolloClient_Subscription.re b/src/ApolloClient_Subscription.re index 467b3cd..60cc13d 100644 --- a/src/ApolloClient_Subscription.re +++ b/src/ApolloClient_Subscription.re @@ -1,17 +1,23 @@ module Types = ApolloClient_Types; -type error = {. "message": string}; - type variant('a) = | Data('a) - | Error(error) + | Error(Types.apolloError) | Loading | NoData; type result('a) = { data: option('a), loading: bool, - error: option(error), + error: option(Types.apolloError), +}; + +module Raw = { + type result('raw_t) = { + data: Js.Nullable.t('raw_t), + loading: bool, + error: Js.Nullable.t(Types.apolloError), + }; }; [@bs.module "graphql-tag"] external gql: Types.gql = "default"; @@ -19,7 +25,7 @@ type result('a) = { [@bs.deriving abstract] type options('raw_t, 'raw_t_variables) = { [@bs.optional] - variables: Js.Json.t, + variables: 'raw_t_variables, [@bs.optional] skip: bool, [@bs.optional] @@ -31,33 +37,33 @@ type options('raw_t, 'raw_t_variables) = { [@bs.module "@apollo/client"] external useSubscription: (Types.queryString, options('raw_t, 'raw_t_variables)) => - { - . - "data": Js.Nullable.t('raw_t), - "loading": bool, - "error": Js.Nullable.t(error), - } = + Raw.result('raw_t) = "useSubscription"; let useSubscription: - ( - ~variables: Js.Json.t=?, - ~client: ApolloClient_Client.t=?, - ~skip: bool=?, - Types.graphqlDefinition('t, 'raw_t) - ) => - (variant('t), result('t)) = - (~variables=?, ~client=?, ~skip=?, (parse, query, _)) => { + type t t_variables raw_t raw_t_variables. + ( + ~variables: Js.Json.t=?, + ~client: ApolloClient_Client.t=?, + ~skip: bool=?, + (module Types.Operation with + type t = t and + type Raw.t = raw_t and + type Raw.t_variables = raw_t_variables) + ) => + (variant(t), result(t)) = + (~variables=?, ~client=?, ~skip=?, (module Operation)) => { let jsResult = useSubscription( - gql(. query), + gql(. Operation.query), options(~variables?, ~client?, ~skip?, ()), ); let result = { - data: jsResult##data->Js.Nullable.toOption->Belt.Option.map(parse), - loading: jsResult##loading, - error: jsResult##error->Js.Nullable.toOption, + data: + jsResult.data->Js.Nullable.toOption->Belt.Option.map(Operation.parse), + loading: jsResult.loading, + error: jsResult.error->Js.Nullable.toOption, }; ( diff --git a/src/ApolloClient_Types.re b/src/ApolloClient_Types.re index 2d41f37..8b98df4 100644 --- a/src/ApolloClient_Types.re +++ b/src/ApolloClient_Types.re @@ -14,14 +14,41 @@ type gql = (. string) => queryString; * An abstract type to describe an Apollo Link object. */ type apolloLink; +type documentNode; /** * An abstract type to describe an Apollo Cache object. */ type apolloCache; +type networkError = {statusCode: int}; + type apolloErrorExtensions = {code: Js.Nullable.t(string)}; +module Observable = { + type t('t); + type subscriptionObserver('t) = { + closed: bool, + next: 't => unit, + error: Js.Json.t => unit, + complete: unit => unit, + }; + + type subscription = { + closed: bool, + unsubscribe: unit => unit, + }; + + [@bs.send] + external subscribe: (t('t), subscriptionObserver('t)) => subscription = + "subscribe"; + + type subscriptionObserverCb = unit => unit; + [@bs.module "@apollo/client"] [@bs.new] + external make: subscriptionObserver('t) => subscriptionObserverCb = + "Observable"; +}; + type graphqlError = { message: string, name: Js.Nullable.t(string), @@ -36,6 +63,44 @@ type executionResult('raw_t) = { data: Js.Nullable.t('raw_t), }; +type apolloError = { + graphQLErrors: Js.Nullable.t(array(graphqlError)), + networkError: Js.Nullable.t(string), +}; + +type operation('raw_t_variables) = { + query: documentNode, + variables: 'raw_t_variables, + operationName: string, + extensions: Js.Json.t, + setContext: Js.Json.t => Js.Json.t, + getContext: unit => Js.Json.t, +}; + +type errorResponse('raw_t, 'raw_t_variables) = { + graphQLErrors: Js.Nullable.t(Js.Array.t(graphqlError)), + networkError: Js.Nullable.t(networkError), + response: Js.Nullable.t(executionResult('raw_t)), + operation: operation('raw_t_variables), + forward: operation('raw_t_variables) => Observable.subscription, +}; + +/* + apollo link ws + */ + +type webSocketLinkOptions = { + reconnect: bool, + connectionParams: option(Js.Json.t), +}; + +type webSocketLink = { + uri: string, + options: webSocketLinkOptions, +}; + +type splitTest = {query: documentNode}; + module type Definition = { let query: string; @@ -49,12 +114,6 @@ module type Definition = { let serialize: t => Raw.t; }; -type apolloError = { - message: string, - graphQLErrors: Js.Nullable.t(array(graphqlError)), - networkError: Js.Nullable.t(string), -}; - /** * apollo-client/src/core/networkStatus */ @@ -118,16 +177,6 @@ let errorPolicyToJs = errorPolicy => | All => "all" }; -type parse('raw_t, 't) = 'raw_t => 't; -type serialize('t, 'raw_t) = 't => 'raw_t; -type query = string; - -type graphqlDefinition('t, 'raw_t) = ( - parse('raw_t, 't), - query, - serialize('t, 'raw_t), -); - module Context = { type t = Js.Dict.t(string); let make = (context): t => Js.Dict.fromList(context); From da84066dce9242200fa1fee58be461a6965f8d19 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Fri, 5 Jun 2020 10:32:59 +0800 Subject: [PATCH 09/13] Add no required variables functionality --- src/ApolloClient_Query.re | 165 ++++++++++++++++++++++++++++++++++---- src/ApolloClient_Types.re | 5 ++ 2 files changed, 156 insertions(+), 14 deletions(-) diff --git a/src/ApolloClient_Query.re b/src/ApolloClient_Query.re index b15fd85..9efbe78 100644 --- a/src/ApolloClient_Query.re +++ b/src/ApolloClient_Query.re @@ -141,7 +141,7 @@ let useQuery: type t t_variables raw_t raw_t_variables. ( ~client: ApolloClient_Client.t=?, - ~variables: raw_t_variables=?, + ~variables: raw_t_variables, ~notifyOnNetworkStatusChange: bool=?, ~fetchPolicy: Types.fetchPolicy=?, ~errorPolicy: Types.errorPolicy=?, @@ -156,7 +156,7 @@ let useQuery: queryResult(t, raw_t, raw_t_variables) = ( ~client=?, - ~variables=?, + ~variables, ~notifyOnNetworkStatusChange=?, ~fetchPolicy=?, ~errorPolicy=?, @@ -169,7 +169,7 @@ let useQuery: useQueryJs( gql(. Operation.query), options( - ~variables?, + ~variables, ~client?, ~notifyOnNetworkStatusChange?, ~fetchPolicy=?fetchPolicy->Belt.Option.map(Types.fetchPolicyToJs), @@ -245,6 +245,45 @@ let useQuery: ); }; +let useQuery0: + type t t_variables raw_t raw_t_variables. + ( + ~client: ApolloClient_Client.t=?, + ~notifyOnNetworkStatusChange: bool=?, + ~fetchPolicy: Types.fetchPolicy=?, + ~errorPolicy: Types.errorPolicy=?, + ~skip: bool=?, + ~pollInterval: int=?, + ~context: Types.Context.t=?, + (module Types.OperationNoRequiredVars with + type t = t and + type Raw.t = raw_t and + type Raw.t_variables = raw_t_variables) + ) => + queryResult(t, raw_t, raw_t_variables) = + ( + ~client=?, + ~notifyOnNetworkStatusChange=?, + ~fetchPolicy=?, + ~errorPolicy=?, + ~skip=?, + ~pollInterval=?, + ~context=?, + (module Operation), + ) => { + useQuery( + ~client?, + ~variables=Operation.makeDefaultVariables(), + ~notifyOnNetworkStatusChange?, + ~fetchPolicy?, + ~errorPolicy?, + ~skip?, + ~pollInterval?, + ~context?, + (module Operation), + ); + }; + let useQueryLegacy: type t t_variables raw_t raw_t_variables. ( @@ -273,17 +312,84 @@ let useQueryLegacy: ~context=?, (module Operation), ) => { + let jsResult = + useQueryJs( + gql(. Operation.query), + options( + ~variables?, + ~client?, + ~notifyOnNetworkStatusChange?, + ~fetchPolicy=?fetchPolicy->Belt.Option.map(Types.fetchPolicyToJs), + ~errorPolicy=?errorPolicy->Belt.Option.map(Types.errorPolicyToJs), + ~skip?, + ~pollInterval?, + ~context?, + (), + ), + ); + let result = - useQuery( - ~client?, - ~variables?, - ~notifyOnNetworkStatusChange?, - ~fetchPolicy?, - ~errorPolicy?, - ~skip?, - ~pollInterval?, - ~context?, - (module Operation), + React.useMemo1( + () => + { + data: + jsResult##data + ->Js.Nullable.toOption + ->Belt.Option.flatMap(data => + switch (Operation.parse(data)) { + | parsedData => Some(parsedData) + | exception _ => None + } + ), + loading: jsResult##loading, + error: jsResult##error->Js.Nullable.toOption, + networkStatus: + ApolloClient_Types.toNetworkStatus(jsResult##networkStatus), + refetch: (~variables=?, ()) => + jsResult##refetch(Js.Nullable.fromOption(variables)) + |> Js.Promise.then_(result => + Operation.parse( + result.data->Js.Nullable.toOption->Belt.Option.getExn, + ) + |> Js.Promise.resolve + ), + rawFetchMore: (~variables=?, ~updateQuery, ()) => + jsResult##fetchMore({Raw.variables, Raw.updateQuery}), + fetchMore: (~variables=?, ~updateQuery, ()) => { + jsResult##fetchMore({ + Raw.variables, + Raw.updateQuery: + (previousResult, {fetchMoreResult, variables}) => { + let result = + updateQuery( + Operation.parse(previousResult), + { + fetchMoreResult: + switch (Js.Nullable.toOption(fetchMoreResult)) { + | None => None + | Some(fetchMoreResult) => + Some(Operation.parse(fetchMoreResult)) + }, + variables: Js.Nullable.toOption(variables), + }, + ); + Operation.serialize(result); + }, + }); + }, + stopPolling: () => jsResult##stopPolling(), + startPolling: interval => jsResult##startPolling(interval), + subscribeToMore: (~document, ~variables=?, ~updateQuery=?, ()) => + jsResult##subscribeToMore( + subscribeToMoreOptionsJs( + ~document, + ~variables?, + ~updateQuery?, + (), + ), + ), + }, + [|jsResult|], ); let simple = @@ -302,6 +408,33 @@ let useQueryLegacy: }; module Extend = (M: Types.Operation) => { + let use = + ( + ~client=?, + ~variables, + ~notifyOnNetworkStatusChange=?, + ~fetchPolicy=?, + ~errorPolicy=?, + ~skip=?, + ~pollInterval=?, + ~context=?, + (), + ) => { + useQuery( + ~client?, + ~variables, + ~notifyOnNetworkStatusChange?, + ~fetchPolicy?, + ~errorPolicy?, + ~skip?, + ~pollInterval?, + ~context?, + (module M), + ); + }; +}; + +module ExtendNoRequiredVars = (M: Types.OperationNoRequiredVars) => { let use = ( ~client=?, @@ -316,7 +449,11 @@ module Extend = (M: Types.Operation) => { ) => { useQuery( ~client?, - ~variables?, + ~variables= + switch (variables) { + | Some(variables) => variables + | None => M.makeDefaultVariables() + }, ~notifyOnNetworkStatusChange?, ~fetchPolicy?, ~errorPolicy?, diff --git a/src/ApolloClient_Types.re b/src/ApolloClient_Types.re index 8b98df4..45f3389 100644 --- a/src/ApolloClient_Types.re +++ b/src/ApolloClient_Types.re @@ -194,3 +194,8 @@ module type Operation = { let parse: Raw.t => t; let serialize: t => Raw.t; }; + +module type OperationNoRequiredVars = { + include Operation; + let makeDefaultVariables: unit => Raw.t_variables; +}; From 4ee0931c6a7f2a2e825c3bb63bc568cddec8a7d1 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Thu, 18 Jun 2020 13:31:07 +0800 Subject: [PATCH 10/13] Compatibility upgrade and more typesafe API --- src/ApolloClient.re | 2 + src/ApolloClient_ApolloLink.re | 1 + src/ApolloClient_Mutation.re | 241 +++++++++++++++++++++++++++++++-- src/ApolloClient_Query.re | 9 +- 4 files changed, 237 insertions(+), 16 deletions(-) diff --git a/src/ApolloClient.re b/src/ApolloClient.re index 4c19c9f..312050b 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -3,6 +3,7 @@ module Query = ApolloClient_Query; module Provider = ApolloClient_Provider; module Subscription = ApolloClient_Subscription; module Client = ApolloClient_Client; +module Link = ApolloClient_ApolloLink; /** This is probably the one hook you'll use the most. A quick demo: @@ -154,6 +155,7 @@ let useQueryLegacy = Query.useQueryLegacy; */ let useMutation = Mutation.useMutation; let useMutationLegacy = Mutation.useMutationLegacy; +let useMutationWithVariables = Mutation.useMutationWithVariables; let toReadQueryOptions = result => { "query": Client.gql(. result##query), diff --git a/src/ApolloClient_ApolloLink.re b/src/ApolloClient_ApolloLink.re index b125a7b..cded175 100644 --- a/src/ApolloClient_ApolloLink.re +++ b/src/ApolloClient_ApolloLink.re @@ -71,6 +71,7 @@ module LinkContext = { ([@bs.uncurry] ((request, context) => Js.Json.t)) => Types.apolloLink = "setContext"; + [@bs.module "@apollo/link-context"] external setContextPromise: ((request, context) => Js.Promise.t(Js.Json.t)) => Types.apolloLink = "setContext"; diff --git a/src/ApolloClient_Mutation.re b/src/ApolloClient_Mutation.re index 71fa6f2..93dbdbd 100644 --- a/src/ApolloClient_Mutation.re +++ b/src/ApolloClient_Mutation.re @@ -72,19 +72,37 @@ type jsMutate('raw_t, 'raw_t_variables) = (. options('raw_t, 'raw_t_variables)) => Js.Promise.t(Execution.jsExecutionResult('raw_t)); -type mutation('t, 'raw_t, 'raw_t_variables) = +type mutation0('t, 'raw_t, 'raw_t_variables) = ( - ~variables: 'raw_t_variables=?, ~client: ApolloClient_Client.t=?, ~refetchQueries: Execution.refetchQueries('raw_t)=?, ~awaitRefetchQueries: bool=?, ~optimisticResponse: 't=?, + ~variables: 'raw_t_variables=?, unit ) => Js.Promise.t( (Execution.executionVariantResult('t), Execution.executionResult('t)), ); +type mutation('t, 'raw_t, 'raw_t_variables) = + ( + ~client: ApolloClient_Client.t=?, + ~refetchQueries: Execution.refetchQueries('raw_t)=?, + ~awaitRefetchQueries: bool=?, + ~optimisticResponse: 't=?, + 'raw_t_variables + ) => + Js.Promise.t( + (Execution.executionVariantResult('t), Execution.executionResult('t)), + ); + +type mutationNoVars('t, 'raw_t, 'raw_t_variables) = + unit => + Js.Promise.t( + (Execution.executionVariantResult('t), Execution.executionResult('t)), + ); + [@bs.module "@apollo/client"] external useMutationJs: (. Types.queryString, options('raw_t, 'raw_t_variables)) => @@ -97,7 +115,6 @@ let useMutation: type t raw_t raw_t_variables. ( ~client: ApolloClient_Client.t=?, - ~variables: raw_t_variables=?, ~refetchQueries: Execution.refetchQueries(raw_t)=?, ~awaitRefetchQueries: bool=?, ~update: (ApolloClient_Client.t, mutationResult(raw_t)) => unit=?, @@ -110,7 +127,6 @@ let useMutation: (mutation(t, raw_t, raw_t_variables), controlledResult(t)) = ( ~client=?, - ~variables=?, ~refetchQueries=?, ~awaitRefetchQueries=?, ~update=?, @@ -122,7 +138,6 @@ let useMutation: gql(. Operation.query), options( ~client?, - ~variables?, ~refetchQueries?, ~awaitRefetchQueries?, ~update?, @@ -140,16 +155,15 @@ let useMutation: React.useMemo1( ( (), - ~variables=?, ~client=?, ~refetchQueries=?, ~awaitRefetchQueries=?, ~optimisticResponse=?, - (), + variables, ) => jsMutate(. options( - ~variables?, + ~variables, ~client?, ~refetchQueries?, ~awaitRefetchQueries?, @@ -186,7 +200,7 @@ let useMutation: (simple, full) |> Js.Promise.resolve; }), - [|variables|], + [||], ); let full = @@ -207,11 +221,152 @@ let useMutation: (mutate, full); }; +let useMutationWithVariables: + type t raw_t raw_t_variables. + ( + ~client: ApolloClient_Client.t=?, + ~refetchQueries: Execution.refetchQueries(raw_t)=?, + ~awaitRefetchQueries: bool=?, + ~update: (ApolloClient_Client.t, mutationResult(raw_t)) => unit=?, + ~optimisticResponse: t=?, + ~variables: raw_t_variables, + (module Types.Operation with + type t = t and + type Raw.t = raw_t and + type Raw.t_variables = raw_t_variables) + ) => + (mutationNoVars(t, raw_t, raw_t_variables), controlledResult(t)) = + ( + ~client=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~update=?, + ~optimisticResponse=?, + ~variables, + (module Operation), + ) => { + let (jsMutate, jsResult) = + useMutationJs(. + gql(. Operation.query), + options( + ~client?, + ~variables, + ~refetchQueries?, + ~awaitRefetchQueries?, + ~update?, + ~optimisticResponse=? + switch (optimisticResponse) { + | Some(optimisticResponse) => + Some(Operation.serialize(optimisticResponse)) + | None => None + }, + (), + ), + ); + + let mutate = () => + jsMutate(. options()) + |> Js.Promise.then_(jsResult => { + let full = + Execution.{ + data: + Js.Nullable.toOption(jsResult##data) + ->Belt.Option.map(Operation.parse), + errors: + switch (Js.Nullable.toOption(jsResult##errors)) { + | Some(errors) when Js.Array.length(errors) > 0 => + Some(errors) + | _ => None + }, + }; + + let simple: Execution.executionVariantResult(Operation.t) = + switch (full) { + | {errors: Some(errors)} => Errors(errors) + | {data: Some(data)} => Data(data) + + | {errors: None, data: None} => NoData + }; + + (simple, full) |> Js.Promise.resolve; + }); + + let full = + React.useMemo1( + () => + { + loading: jsResult##loading, + called: jsResult##called, + data: + jsResult##data + ->Js.Nullable.toOption + ->Belt.Option.map(Operation.parse), + error: jsResult##error->Js.Nullable.toOption, + }, + [|jsResult|], + ); + + (mutate, full); + }; + +let useMutation0: + type t raw_t raw_t_variables. + ( + ~client: ApolloClient_Client.t=?, + ~refetchQueries: Execution.refetchQueries(raw_t)=?, + ~awaitRefetchQueries: bool=?, + ~update: (ApolloClient_Client.t, mutationResult(raw_t)) => unit=?, + ~optimisticResponse: t=?, + (module Types.OperationNoRequiredVars with + type t = t and + type Raw.t = raw_t and + type Raw.t_variables = raw_t_variables) + ) => + (mutation0(t, raw_t, raw_t_variables), controlledResult(t)) = + ( + ~client=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~update=?, + ~optimisticResponse=?, + (module Operation), + ) => { + let (mutate, full) = + useMutation( + ~client?, + ~refetchQueries?, + ~awaitRefetchQueries?, + ~update?, + ~optimisticResponse?, + (module Operation), + ); + let mutate = + ( + ~client=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~optimisticResponse=?, + ~variables=?, + (), + ) => { + mutate( + ~client?, + ~refetchQueries?, + ~awaitRefetchQueries?, + ~optimisticResponse?, + switch (variables) { + | Some(variables) => variables + | None => Operation.makeDefaultVariables() + }, + ); + }; + (mutate, full); + }; + let useMutationLegacy: type t raw_t raw_t_variables. ( ~client: ApolloClient_Client.t=?, - ~variables: raw_t_variables=?, ~refetchQueries: Execution.refetchQueries(raw_t)=?, ~awaitRefetchQueries: bool=?, ~update: (ApolloClient_Client.t, mutationResult(raw_t)) => unit=?, @@ -228,7 +383,6 @@ let useMutationLegacy: ) = ( ~client=?, - ~variables=?, ~refetchQueries=?, ~awaitRefetchQueries=?, ~update=?, @@ -238,7 +392,6 @@ let useMutationLegacy: let (mutate, result) = useMutation( ~client?, - ~variables?, ~refetchQueries?, ~awaitRefetchQueries?, ~update?, @@ -265,7 +418,6 @@ module Extend = (M: Types.Operation) => { let use = ( ~client=?, - ~variables=?, ~refetchQueries=?, ~awaitRefetchQueries=?, ~update=?, @@ -274,7 +426,6 @@ module Extend = (M: Types.Operation) => { ) => { useMutation( ~client?, - ~variables?, ~refetchQueries?, ~awaitRefetchQueries?, ~update?, @@ -282,4 +433,66 @@ module Extend = (M: Types.Operation) => { (module M), ); }; + let useWithVariables = + ( + ~client=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~update=?, + ~optimisticResponse=?, + variables, + ) => { + useMutationWithVariables( + ~client?, + ~refetchQueries?, + ~awaitRefetchQueries?, + ~update?, + ~optimisticResponse?, + ~variables, + (module M), + ); + }; +}; + +module ExtendNoRequiredVars = (M: Types.OperationNoRequiredVars) => { + /** + Use hook for apollo client + */ + let use = + ( + ~client=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~update=?, + ~optimisticResponse=?, + (), + ) => { + useMutation( + ~client?, + ~refetchQueries?, + ~awaitRefetchQueries?, + ~update?, + ~optimisticResponse?, + (module M), + ); + }; + let useWithVariables = + ( + ~client=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~update=?, + ~optimisticResponse=?, + variables, + ) => { + useMutationWithVariables( + ~client?, + ~refetchQueries?, + ~awaitRefetchQueries?, + ~update?, + ~optimisticResponse?, + ~variables, + (module M), + ); + }; }; diff --git a/src/ApolloClient_Query.re b/src/ApolloClient_Query.re index 9efbe78..cb2003d 100644 --- a/src/ApolloClient_Query.re +++ b/src/ApolloClient_Query.re @@ -408,17 +408,19 @@ let useQueryLegacy: }; module Extend = (M: Types.Operation) => { + /** + Use hook for apollo client + */ let use = ( ~client=?, - ~variables, ~notifyOnNetworkStatusChange=?, ~fetchPolicy=?, ~errorPolicy=?, ~skip=?, ~pollInterval=?, ~context=?, - (), + variables, ) => { useQuery( ~client?, @@ -435,6 +437,9 @@ module Extend = (M: Types.Operation) => { }; module ExtendNoRequiredVars = (M: Types.OperationNoRequiredVars) => { + /** + Use hook for apollo client + */ let use = ( ~client=?, From a599cd8660a9339fc01389257c023ba1f0065c8a Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Wed, 8 Jul 2020 09:21:25 +0800 Subject: [PATCH 11/13] add ssr --- src/ApolloClient.re | 1 + src/ApolloClient_ApolloLink.re | 129 +++++++++++++++++------------- src/ApolloClient_Client.re | 24 +++++- src/ApolloClient_HooksClient.re | 3 - src/ApolloClient_InMemoryCache.re | 2 +- src/ApolloClient_Query.re | 12 +++ src/ApolloClient_Types.re | 7 +- 7 files changed, 117 insertions(+), 61 deletions(-) diff --git a/src/ApolloClient.re b/src/ApolloClient.re index 312050b..902e4a7 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -4,6 +4,7 @@ module Provider = ApolloClient_Provider; module Subscription = ApolloClient_Subscription; module Client = ApolloClient_Client; module Link = ApolloClient_ApolloLink; +module InMemoryCache = ApolloClient_InMemoryCache; /** This is probably the one hook you'll use the most. A quick demo: diff --git a/src/ApolloClient_ApolloLink.re b/src/ApolloClient_ApolloLink.re index cded175..127bf13 100644 --- a/src/ApolloClient_ApolloLink.re +++ b/src/ApolloClient_ApolloLink.re @@ -1,5 +1,6 @@ module Types = ApolloClient_Types; +type t = Types.apolloLink; type fetch; type request; type context; @@ -27,23 +28,46 @@ type nextLink('raw_t, 'raw_t_variables) = type makeCb('raw_t, 'raw_t_variables) = (Types.operation('raw_t_variables), nextLink('raw_t, 'raw_t_variables)) => Types.Observable.t(fetchResult('raw_t)); -external make: makeCb('raw_t, 'raw_t_variables) => Types.apolloLink; +external make: makeCb('raw_t, 'raw_t_variables) => t; /* Bind the method `from`, used to compose links together */ -[@bs.module "@apollo/client"] -external from: array(Types.apolloLink) => Types.apolloLink = "from"; +[@bs.module "@apollo/client"] external from: array(t) => t = "from"; /* Bind the method split. Based on a test send left or right */ [@bs.module "@apollo/client"] -external split: - (Types.splitTest => bool, Types.apolloLink, Types.apolloLink) => - Types.apolloLink = - "split"; +external split: (Types.splitTest => bool, t, t) => t = "split"; + +module RetryLink = { + // serverError is an Error instance with some extra props + // see: https://github.com/apollographql/apollo-client/blob/master/src/link/utils/throwServerError.ts + type serverError = { + statusCode: int, + response: Js.Json.t, + result: Js.Json.t, + }; + type delay = { + initial: int, + max: int, + jitter: bool, + }; + type attempts('raw_t_variables) = { + max: int, + retryIf: + (Js.Nullable.t(serverError), Types.operation('raw_t_variables)) => bool, + }; + type options('raw_t_variables) = { + delay, + attempts: attempts('raw_t_variables), + }; + + [@bs.module "apollo-link-retry"] [@bs.new] + external make: options('raw_t_variables) => t = "RetryLink"; +}; module HttpLink = { [@bs.module "@apollo/client"] [@bs.new] - external jsMake: linkOptions => Types.apolloLink = "HttpLink"; - let createHttpLink = + external jsMake: linkOptions => t = "HttpLink"; + let make = ( ~uri, ~includeExtensions=?, @@ -66,62 +90,59 @@ module HttpLink = { module LinkContext = { /* Bind the setContext method */ - [@bs.module "@apollo/link-context"] - external setContext: - ([@bs.uncurry] ((request, context) => Js.Json.t)) => Types.apolloLink = + [@bs.module "apollo-link-context"] + external setContext: ([@bs.uncurry] ((request, context) => Js.Json.t)) => t = "setContext"; - [@bs.module "@apollo/link-context"] + [@bs.module "apollo-link-context"] external setContextPromise: - ((request, context) => Js.Promise.t(Js.Json.t)) => Types.apolloLink = + ((request, context) => Js.Promise.t(Js.Json.t)) => t = "setContext"; }; module LinkError = { /* Bind the onError method */ - [@bs.module "@apollo/link-error"] + [@bs.module "apollo-link-error"] external onError: - (Types.errorResponse('raw_t, 'raw_t_variables) => unit) => - Types.apolloLink = + (Types.errorResponse('raw_t, 'raw_t_variables) => unit) => t = "onError"; }; /* bind apollo-link-ws */ -[@bs.module "@apollo/link-ws"] [@bs.new] -external webSocketLink: Types.webSocketLink => Types.apolloLink = - "WebSocketLink"; - -module UploadLink = { - type uploadLinkOptions = { - uri: Js.Nullable.t(string), - fetch: Js.Nullable.t(fetch), - fetchOptions: Js.Nullable.t(Js.t({.})), - credentials: Js.Nullable.t(string), - headers: Js.Nullable.t(Js.Json.t), - includeExtensions: Js.Nullable.t(bool), - }; +[@bs.module "apollo-link-ws"] [@bs.new] +external webSocketLink: Types.webSocketLink => t = "WebSocketLink"; - /* Bind createUploadLink function from apollo upload link */ - [@bs.module "apollo-upload-client"] - external jsMake: uploadLinkOptions => Types.apolloLink = "createUploadLink"; - let make = - ( - ~uri=?, - ~fetch=?, - ~fetchOptions=?, - ~credentials=?, - ~headers=?, - ~includeExtensions=?, - (), - ) => - jsMake( - Js.Nullable.{ - uri: fromOption(uri), - fetch: fromOption(fetch), - fetchOptions: fromOption(fetchOptions), - credentials: fromOption(credentials), - headers: fromOption(headers), - includeExtensions: fromOption(includeExtensions), - }, - ); -}; +// module UploadLink = { +// type uploadLinkOptions = { +// uri: Js.Nullable.t(string), +// fetch: Js.Nullable.t(fetch), +// fetchOptions: Js.Nullable.t(Js.t({.})), +// credentials: Js.Nullable.t(string), +// headers: Js.Nullable.t(Js.Json.t), +// includeExtensions: Js.Nullable.t(bool), +// }; + +// /* Bind createUploadLink function from apollo upload link */ +// [@bs.module "apollo-upload-client"] +// external jsMake: uploadLinkOptions => t = "createUploadLink"; +// let make = +// ( +// ~uri=?, +// ~fetch=?, +// ~fetchOptions=?, +// ~credentials=?, +// ~headers=?, +// ~includeExtensions=?, +// (), +// ) => +// jsMake( +// Js.Nullable.{ +// uri: fromOption(uri), +// fetch: fromOption(fetch), +// fetchOptions: fromOption(fetchOptions), +// credentials: fromOption(credentials), +// headers: fromOption(headers), +// includeExtensions: fromOption(includeExtensions), +// }, +// ); +// }; diff --git a/src/ApolloClient_Client.re b/src/ApolloClient_Client.re index 4543708..7e0db0c 100644 --- a/src/ApolloClient_Client.re +++ b/src/ApolloClient_Client.re @@ -79,7 +79,7 @@ external mutate: "mutate"; [@bs.send] external resetStore: t => Js.Promise.t(unit) = "resetStore"; -type apolloClientObjectParam = { +type options = { link: Types.apolloLink, cache: Types.apolloCache, ssrMode: option(bool), @@ -89,7 +89,27 @@ type apolloClientObjectParam = { }; [@bs.module "@apollo/client"] [@bs.new] -external createApolloClientJS: apolloClientObjectParam => t = "ApolloClient"; +external makeJs: options => t = "ApolloClient"; + +let make = + ( + ~link, + ~cache, + ~ssrMode=?, + ~ssrForceFetchDelay=?, + ~connectToDevTools=?, + ~queryDeduplication=?, + (), + ) => { + makeJs({ + link, + cache, + ssrMode, + ssrForceFetchDelay, + connectToDevTools, + queryDeduplication, + }); +}; [@bs.module "graphql-tag"] external gql: Types.gql = "default"; diff --git a/src/ApolloClient_HooksClient.re b/src/ApolloClient_HooksClient.re index 23f261f..c3baf0f 100644 --- a/src/ApolloClient_HooksClient.re +++ b/src/ApolloClient_HooksClient.re @@ -67,6 +67,3 @@ external query: (ApolloClient_Client.t, options('data)) => Js.Promise.t(queryResult('data)) = "query"; - -[@bs.module "../../../apolloClient"] -external client: ApolloClient_Client.t = "default"; diff --git a/src/ApolloClient_InMemoryCache.re b/src/ApolloClient_InMemoryCache.re index b447396..9c0be93 100644 --- a/src/ApolloClient_InMemoryCache.re +++ b/src/ApolloClient_InMemoryCache.re @@ -33,7 +33,7 @@ external makeApolloInMemoryCacheParams: ) => _; -let createInMemoryCache = (~dataIdFromObject=?, ~possibleTypes=?, ()) => { +let make = (~dataIdFromObject=?, ~possibleTypes=?, ()) => { /* Apollo Client, looks for key in Object. Doesn't check if value is null */ apolloInMemoryCache( makeApolloInMemoryCacheParams(~dataIdFromObject?, ~possibleTypes?), diff --git a/src/ApolloClient_Query.re b/src/ApolloClient_Query.re index cb2003d..cb05242 100644 --- a/src/ApolloClient_Query.re +++ b/src/ApolloClient_Query.re @@ -110,6 +110,8 @@ type options('raw_t_variables) = { pollInterval: int, [@bs.optional] context: Types.Context.t, + [@bs.optional] + ssr: bool, }; type refetchResult('raw_t) = {data: Js.Nullable.t('raw_t)}; @@ -148,6 +150,7 @@ let useQuery: ~skip: bool=?, ~pollInterval: int=?, ~context: Types.Context.t=?, + ~ssr: bool=?, (module Types.Operation with type t = t and type Raw.t = raw_t and @@ -163,6 +166,7 @@ let useQuery: ~skip=?, ~pollInterval=?, ~context=?, + ~ssr=?, (module Operation), ) => { let jsResult = @@ -177,6 +181,7 @@ let useQuery: ~skip?, ~pollInterval?, ~context?, + ~ssr?, (), ), ); @@ -255,6 +260,7 @@ let useQuery0: ~skip: bool=?, ~pollInterval: int=?, ~context: Types.Context.t=?, + ~ssr: bool=?, (module Types.OperationNoRequiredVars with type t = t and type Raw.t = raw_t and @@ -269,6 +275,7 @@ let useQuery0: ~skip=?, ~pollInterval=?, ~context=?, + ~ssr=?, (module Operation), ) => { useQuery( @@ -280,6 +287,7 @@ let useQuery0: ~skip?, ~pollInterval?, ~context?, + ~ssr?, (module Operation), ); }; @@ -420,6 +428,7 @@ module Extend = (M: Types.Operation) => { ~skip=?, ~pollInterval=?, ~context=?, + ~ssr=?, variables, ) => { useQuery( @@ -431,6 +440,7 @@ module Extend = (M: Types.Operation) => { ~skip?, ~pollInterval?, ~context?, + ~ssr?, (module M), ); }; @@ -450,6 +460,7 @@ module ExtendNoRequiredVars = (M: Types.OperationNoRequiredVars) => { ~skip=?, ~pollInterval=?, ~context=?, + ~ssr=?, (), ) => { useQuery( @@ -465,6 +476,7 @@ module ExtendNoRequiredVars = (M: Types.OperationNoRequiredVars) => { ~skip?, ~pollInterval?, ~context?, + ~ssr?, (module M), ); }; diff --git a/src/ApolloClient_Types.re b/src/ApolloClient_Types.re index 45f3389..9f3e0b5 100644 --- a/src/ApolloClient_Types.re +++ b/src/ApolloClient_Types.re @@ -14,7 +14,12 @@ type gql = (. string) => queryString; * An abstract type to describe an Apollo Link object. */ type apolloLink; -type documentNode; + +type documentDefinition = { + kind: string, + operation: string, +}; +type documentNode = {definitions: array(documentDefinition)}; /** * An abstract type to describe an Apollo Cache object. From 01db25bf86521b5e94862c51d42fbce42dc0948f Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Sun, 9 Aug 2020 21:46:11 +0800 Subject: [PATCH 12/13] Use new makeVariables function --- src/ApolloClient_Client.re | 42 +++--- src/ApolloClient_HooksClient.re | 13 +- src/ApolloClient_InMemoryCache.re | 17 ++- src/ApolloClient_Mutation.re | 220 ++++++++++++++++++++---------- src/ApolloClient_Query.re | 186 ++++++++++++++++--------- src/ApolloClient_Subscription.re | 7 +- src/ApolloClient_Types.re | 8 +- 7 files changed, 327 insertions(+), 166 deletions(-) diff --git a/src/ApolloClient_Client.re b/src/ApolloClient_Client.re index 7e0db0c..793e727 100644 --- a/src/ApolloClient_Client.re +++ b/src/ApolloClient_Client.re @@ -39,7 +39,7 @@ type subscribeToMoreOptions = { type fetchMoreOptions('raw_t, 'raw_t_variables) = { variables: option('raw_t_variables), - updateQuery: updateQueryT('raw_t, 'raw_t_variables), + updateQuery: option(updateQueryT('raw_t, 'raw_t_variables)), }; type queryResult('raw_t, 'raw_t_variables) = { @@ -113,53 +113,61 @@ let make = [@bs.module "graphql-tag"] external gql: Types.gql = "default"; -module ReadQuery = (Definition: Types.Definition) => { +module ReadQuery = (Operation: Types.Operation) => { type readQueryOptions = { query: Types.queryString, - variables: Js.Nullable.t(Definition.Raw.t_variables), + variables: Js.Nullable.t(Operation.Raw.t_variables), }; - type response = option(Definition.t); + type response = option(Operation.t); [@bs.send] - external readQuery: (t, readQueryOptions) => Js.Nullable.t(Definition.Raw.t) = + external readQuery: (t, readQueryOptions) => Js.Nullable.t(Operation.Raw.t) = "readQuery"; - let graphqlQueryAST = gql(. Definition.query); - let apolloDataToRecord: Js.Nullable.t(Definition.Raw.t) => response = + let graphqlQueryAST = gql(. Operation.query); + let apolloDataToRecord: Js.Nullable.t(Operation.Raw.t) => response = apolloData => - Js.Nullable.toOption(apolloData)->(Belt.Option.map(Definition.parse)); + Js.Nullable.toOption(apolloData)->(Belt.Option.map(Operation.parse)); - let make = (~client, ~variables: option(Definition.Raw.t_variables)=?, ()) => + let make = (~client, ~variables: option(Operation.t_variables)=?, ()) => readQuery( client, - {query: graphqlQueryAST, variables: Js.Nullable.fromOption(variables)}, + {query: graphqlQueryAST, variables: + Js.Nullable.fromOption(switch(variables) { + | Some(variables) => Some(Operation.serializeVariables(variables)) + | None => None + })}, ) ->apolloDataToRecord; }; -module WriteQuery = (Definition: Types.Definition) => { +module WriteQuery = (Operation: Types.Operation) => { type writeQueryOptions = { query: Types.queryString, - variables: Js.Nullable.t(Definition.Raw.t_variables), - data: Definition.t, + variables: Js.Nullable.t(Operation.Raw.t_variables), + data: Operation.t, }; [@bs.send] external writeQuery: (t, writeQueryOptions) => unit = "writeQuery"; - let graphqlQueryAST = gql(. Definition.query); + let graphqlQueryAST = gql(. Operation.query); let make = ( ~client, - ~variables: option(Definition.Raw.t_variables)=?, - ~data: Definition.t, + ~variables: option(Operation.t_variables)=?, + ~data: Operation.t, (), ) => writeQuery( client, { query: graphqlQueryAST, - variables: Js.Nullable.fromOption(variables), + variables: + Js.Nullable.fromOption(switch(variables) { + | Some(variables) => Some(Operation.serializeVariables(variables)) + | None => None + }), data, }, ); diff --git a/src/ApolloClient_HooksClient.re b/src/ApolloClient_HooksClient.re index c3baf0f..d874cfe 100644 --- a/src/ApolloClient_HooksClient.re +++ b/src/ApolloClient_HooksClient.re @@ -26,9 +26,9 @@ external doMakeOptions: options('data); let makeOptions: - type t raw_t raw_t_variables. + type t raw_t t_variables raw_t_variables. ( - ~variables: raw_t_variables=?, + ~variables: t_variables=?, ~notifyOnNetworkStatusChange: bool=?, ~fetchPolicy: Types.fetchPolicy=?, ~errorPolicy: Types.errorPolicy=?, @@ -37,6 +37,7 @@ let makeOptions: (module Types.Operation with type t = t and type Raw.t = raw_t and + type t_variables = t_variables and type Raw.t_variables = raw_t_variables) ) => options(t) = @@ -47,11 +48,13 @@ let makeOptions: ~errorPolicy=?, ~pollInterval=?, ~context=?, - (module Definition), + (module Operation), ) => { doMakeOptions( - ~query=gql(. Definition.query), - ~variables?, + ~query=gql(. Operation.query), + ~variables=?{switch(variables) { + | Some(variables) => Some(Operation.serializeVariables(variables)) + | None => None}}, ~notifyOnNetworkStatusChange?, ~fetchPolicy=? fetchPolicy->Belt.Option.map(f => Types.fetchPolicyToJs(f)), diff --git a/src/ApolloClient_InMemoryCache.re b/src/ApolloClient_InMemoryCache.re index 9c0be93..badc642 100644 --- a/src/ApolloClient_InMemoryCache.re +++ b/src/ApolloClient_InMemoryCache.re @@ -24,18 +24,29 @@ external apolloInMemoryCache: 'a => Types.apolloCache = "InMemoryCache"; [@bs.send.pipe: 't] external restore: inMemoryCacheRestoreData => Types.apolloCache = "restore"; +type pagination; + +[@bs.module "@apollo/client/utilities"] +external relayStylePagination: array(string) => pagination = + "relayStylePagination"; + /* Instantiate a new cache object */ [@bs.obj] external makeApolloInMemoryCacheParams: ( ~possibleTypes: Js.Dict.t(array(string))=?, - ~dataIdFromObject: Js.t({..}) => string=? + ~dataIdFromObject: Js.t({..}) => string=?, + ~typePolicies: Js.t({..})=? ) => _; -let make = (~dataIdFromObject=?, ~possibleTypes=?, ()) => { +let make = (~dataIdFromObject=?, ~possibleTypes=?, ~typePolicies=?, ()) => { /* Apollo Client, looks for key in Object. Doesn't check if value is null */ apolloInMemoryCache( - makeApolloInMemoryCacheParams(~dataIdFromObject?, ~possibleTypes?), + makeApolloInMemoryCacheParams( + ~dataIdFromObject?, + ~possibleTypes?, + ~typePolicies?, + ), ); }; diff --git a/src/ApolloClient_Mutation.re b/src/ApolloClient_Mutation.re index 93dbdbd..50f5d92 100644 --- a/src/ApolloClient_Mutation.re +++ b/src/ApolloClient_Mutation.re @@ -23,11 +23,6 @@ module Execution = { data: option('a), errors: option(array(Types.graphqlError)), }; - - type executionVariantResult('a) = - | Data('a) - | Errors(array(Types.graphqlError)) - | NoData; }; /* The type of the 'full' result returned by the hook */ @@ -72,36 +67,29 @@ type jsMutate('raw_t, 'raw_t_variables) = (. options('raw_t, 'raw_t_variables)) => Js.Promise.t(Execution.jsExecutionResult('raw_t)); -type mutation0('t, 'raw_t, 'raw_t_variables) = +type mutation0('t, 'raw_t, 't_variables) = ( ~client: ApolloClient_Client.t=?, ~refetchQueries: Execution.refetchQueries('raw_t)=?, ~awaitRefetchQueries: bool=?, ~optimisticResponse: 't=?, - ~variables: 'raw_t_variables=?, + ~variables: 't_variables=?, unit ) => - Js.Promise.t( - (Execution.executionVariantResult('t), Execution.executionResult('t)), - ); + Js.Promise.t(Execution.executionResult('t)); -type mutation('t, 'raw_t, 'raw_t_variables) = +type mutation('t, 'raw_t, 't_variables) = ( ~client: ApolloClient_Client.t=?, ~refetchQueries: Execution.refetchQueries('raw_t)=?, ~awaitRefetchQueries: bool=?, ~optimisticResponse: 't=?, - 'raw_t_variables + 't_variables ) => - Js.Promise.t( - (Execution.executionVariantResult('t), Execution.executionResult('t)), - ); + Js.Promise.t(Execution.executionResult('t)); -type mutationNoVars('t, 'raw_t, 'raw_t_variables) = - unit => - Js.Promise.t( - (Execution.executionVariantResult('t), Execution.executionResult('t)), - ); +type mutationNoVars('t, 'raw_t, 't_variables) = + unit => Js.Promise.t(Execution.executionResult('t)); [@bs.module "@apollo/client"] external useMutationJs: @@ -112,7 +100,7 @@ external useMutationJs: exception Error(string); let useMutation: - type t raw_t raw_t_variables. + type t raw_t t_variables raw_t_variables. ( ~client: ApolloClient_Client.t=?, ~refetchQueries: Execution.refetchQueries(raw_t)=?, @@ -122,9 +110,10 @@ let useMutation: (module Types.Operation with type t = t and type Raw.t = raw_t and + type t_variables = t_variables and type Raw.t_variables = raw_t_variables) ) => - (mutation(t, raw_t, raw_t_variables), controlledResult(t)) = + (mutation(t, raw_t, t_variables), controlledResult(t)) = ( ~client=?, ~refetchQueries=?, @@ -163,7 +152,7 @@ let useMutation: ) => jsMutate(. options( - ~variables, + ~variables=Operation.serializeVariables(variables), ~client?, ~refetchQueries?, ~awaitRefetchQueries?, @@ -177,28 +166,18 @@ let useMutation: ), ) |> Js.Promise.then_(jsResult => { - let full = - Execution.{ - data: - Js.Nullable.toOption(jsResult##data) - ->Belt.Option.map(Operation.parse), - errors: - switch (Js.Nullable.toOption(jsResult##errors)) { - | Some(errors) when Js.Array.length(errors) > 0 => - Some(errors) - | _ => None - }, - }; - - let simple: Execution.executionVariantResult(Operation.t) = - switch (full) { - | {errors: Some(errors)} => Errors(errors) - | {data: Some(data)} => Data(data) - - | {errors: None, data: None} => NoData - }; - - (simple, full) |> Js.Promise.resolve; + { + Execution.data: + Js.Nullable.toOption(jsResult##data) + ->Belt.Option.map(Operation.parse), + errors: + switch (Js.Nullable.toOption(jsResult##errors)) { + | Some(errors) when Js.Array.length(errors) > 0 => + Some(errors) + | _ => None + }, + } + |> Js.Promise.resolve }), [||], ); @@ -221,8 +200,8 @@ let useMutation: (mutate, full); }; -let useMutationWithVariables: - type t raw_t raw_t_variables. +let useMutationWithRawVariables: + type t raw_t t_variables raw_t_variables. ( ~client: ApolloClient_Client.t=?, ~refetchQueries: Execution.refetchQueries(raw_t)=?, @@ -233,9 +212,10 @@ let useMutationWithVariables: (module Types.Operation with type t = t and type Raw.t = raw_t and + type t_variables = t_variables and type Raw.t_variables = raw_t_variables) ) => - (mutationNoVars(t, raw_t, raw_t_variables), controlledResult(t)) = + (mutationNoVars(t, raw_t, t_variables), controlledResult(t)) = ( ~client=?, ~refetchQueries=?, @@ -250,7 +230,7 @@ let useMutationWithVariables: gql(. Operation.query), options( ~client?, - ~variables, + ~variables=variables, ~refetchQueries?, ~awaitRefetchQueries?, ~update?, @@ -267,28 +247,97 @@ let useMutationWithVariables: let mutate = () => jsMutate(. options()) |> Js.Promise.then_(jsResult => { - let full = - Execution.{ - data: - Js.Nullable.toOption(jsResult##data) - ->Belt.Option.map(Operation.parse), - errors: - switch (Js.Nullable.toOption(jsResult##errors)) { - | Some(errors) when Js.Array.length(errors) > 0 => - Some(errors) - | _ => None - }, - }; - - let simple: Execution.executionVariantResult(Operation.t) = - switch (full) { - | {errors: Some(errors)} => Errors(errors) - | {data: Some(data)} => Data(data) - - | {errors: None, data: None} => NoData - }; - - (simple, full) |> Js.Promise.resolve; + { + Execution.data: + Js.Nullable.toOption(jsResult##data) + ->Belt.Option.map(Operation.parse), + errors: + switch (Js.Nullable.toOption(jsResult##errors)) { + | Some(errors) when Js.Array.length(errors) > 0 => + Some(errors) + | _ => None + }, + } + |> Js.Promise.resolve + }); + + let full = + React.useMemo1( + () => + { + loading: jsResult##loading, + called: jsResult##called, + data: + jsResult##data + ->Js.Nullable.toOption + ->Belt.Option.map(Operation.parse), + error: jsResult##error->Js.Nullable.toOption, + }, + [|jsResult|], + ); + + (mutate, full); + }; + +let useMutationWithVariables: + type t raw_t t_variables raw_t_variables. + ( + ~client: ApolloClient_Client.t=?, + ~refetchQueries: Execution.refetchQueries(raw_t)=?, + ~awaitRefetchQueries: bool=?, + ~update: (ApolloClient_Client.t, mutationResult(raw_t)) => unit=?, + ~optimisticResponse: t=?, + ~variables: t_variables, + (module Types.Operation with + type t = t and + type Raw.t = raw_t and + type t_variables = t_variables and + type Raw.t_variables = raw_t_variables) + ) => + (mutationNoVars(t, raw_t, t_variables), controlledResult(t)) = + ( + ~client=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~update=?, + ~optimisticResponse=?, + ~variables, + (module Operation), + ) => { + let (jsMutate, jsResult) = + useMutationJs(. + gql(. Operation.query), + options( + ~client?, + ~variables=Operation.serializeVariables(variables), + ~refetchQueries?, + ~awaitRefetchQueries?, + ~update?, + ~optimisticResponse=? + switch (optimisticResponse) { + | Some(optimisticResponse) => + Some(Operation.serialize(optimisticResponse)) + | None => None + }, + (), + ), + ); + + let mutate = () => + jsMutate(. options()) + |> Js.Promise.then_(jsResult => { + { + Execution.data: + Js.Nullable.toOption(jsResult##data) + ->Belt.Option.map(Operation.parse), + errors: + switch (Js.Nullable.toOption(jsResult##errors)) { + | Some(errors) when Js.Array.length(errors) > 0 => + Some(errors) + | _ => None + }, + } + |> Js.Promise.resolve }); let full = @@ -310,7 +359,7 @@ let useMutationWithVariables: }; let useMutation0: - type t raw_t raw_t_variables. + type t raw_t t_variables raw_t_variables. ( ~client: ApolloClient_Client.t=?, ~refetchQueries: Execution.refetchQueries(raw_t)=?, @@ -320,9 +369,10 @@ let useMutation0: (module Types.OperationNoRequiredVars with type t = t and type Raw.t = raw_t and + type t_variables = t_variables and type Raw.t_variables = raw_t_variables) ) => - (mutation0(t, raw_t, raw_t_variables), controlledResult(t)) = + (mutation0(t, raw_t, t_variables), controlledResult(t)) = ( ~client=?, ~refetchQueries=?, @@ -364,7 +414,7 @@ let useMutation0: }; let useMutationLegacy: - type t raw_t raw_t_variables. + type t raw_t t_variables raw_t_variables. ( ~client: ApolloClient_Client.t=?, ~refetchQueries: Execution.refetchQueries(raw_t)=?, @@ -374,10 +424,11 @@ let useMutationLegacy: (module Types.Operation with type t = t and type Raw.t = raw_t and + type t_variables = t_variables and type Raw.t_variables = raw_t_variables) ) => ( - mutation(t, raw_t, raw_t_variables), + mutation(t, raw_t, t_variables), controlledVariantResult(t), controlledResult(t), ) = @@ -452,6 +503,25 @@ module Extend = (M: Types.Operation) => { (module M), ); }; + let useWithRawVariables = + ( + ~client=?, + ~refetchQueries=?, + ~awaitRefetchQueries=?, + ~update=?, + ~optimisticResponse=?, + variables, + ) => { + useMutationWithRawVariables( + ~client?, + ~refetchQueries?, + ~awaitRefetchQueries?, + ~update?, + ~optimisticResponse?, + ~variables, + (module M), + ); + }; }; module ExtendNoRequiredVars = (M: Types.OperationNoRequiredVars) => { diff --git a/src/ApolloClient_Query.re b/src/ApolloClient_Query.re index cb05242..679e832 100644 --- a/src/ApolloClient_Query.re +++ b/src/ApolloClient_Query.re @@ -50,20 +50,22 @@ module Raw = { type fetchMoreOptions('raw_t, 'raw_t_variables) = { variables: option('raw_t_variables), updateQuery: - ('raw_t, updateQueryOptions('raw_t, 'raw_t_variables)) => 'raw_t, + option( + ('raw_t, updateQueryOptions('raw_t, 'raw_t_variables)) => 'raw_t, + ), }; }; -type queryResult('t, 'raw_t, 'raw_t_variables) = { +type queryResult('t, 'raw_t, 't_variables, 'raw_t_variables) = { data: option('t), loading: bool, error: option(Types.apolloError), networkStatus: Types.networkStatus, - refetch: (~variables: 'raw_t_variables=?, unit) => Js.Promise.t('t), + refetch: (~variables: 't_variables=?, unit) => Js.Promise.t('t), fetchMore: ( - ~variables: 'raw_t_variables=?, - ~updateQuery: ('t, updateQueryOptions('t, 'raw_t_variables)) => 't, + ~variables: 't_variables=?, + ~updateQuery: ('t, updateQueryOptions('t, 'raw_t_variables)) => 't=?, unit ) => Js.Promise.t(unit), @@ -74,7 +76,8 @@ type queryResult('t, 'raw_t, 'raw_t_variables) = { 'raw_t, Raw.updateQueryOptions('raw_t, 'raw_t_variables) ) => - 'raw_t, + 'raw_t + =?, unit ) => Js.Promise.t(unit), @@ -83,7 +86,7 @@ type queryResult('t, 'raw_t, 'raw_t_variables) = { subscribeToMore: ( ~document: Types.queryString, - ~variables: 'raw_t_variables=?, + ~variables: 't_variables=?, ~updateQuery: updateQuerySubscribeToMoreT('raw_t, 'raw_t_variables)=?, unit ) => @@ -112,6 +115,8 @@ type options('raw_t_variables) = { context: Types.Context.t, [@bs.optional] ssr: bool, + [@bs.optional] + partialRefetch: bool, }; type refetchResult('raw_t) = {data: Js.Nullable.t('raw_t)}; @@ -143,7 +148,7 @@ let useQuery: type t t_variables raw_t raw_t_variables. ( ~client: ApolloClient_Client.t=?, - ~variables: raw_t_variables, + ~variables: t_variables, ~notifyOnNetworkStatusChange: bool=?, ~fetchPolicy: Types.fetchPolicy=?, ~errorPolicy: Types.errorPolicy=?, @@ -151,12 +156,14 @@ let useQuery: ~pollInterval: int=?, ~context: Types.Context.t=?, ~ssr: bool=?, + ~partialRefetch: bool=?, (module Types.Operation with type t = t and type Raw.t = raw_t and - type Raw.t_variables = raw_t_variables) + type Raw.t_variables = raw_t_variables and + type t_variables = t_variables) ) => - queryResult(t, raw_t, raw_t_variables) = + queryResult(t, raw_t, t_variables, raw_t_variables) = ( ~client=?, ~variables, @@ -167,13 +174,14 @@ let useQuery: ~pollInterval=?, ~context=?, ~ssr=?, + ~partialRefetch=true, (module Operation), ) => { let jsResult = useQueryJs( gql(. Operation.query), options( - ~variables, + ~variables=Operation.serializeVariables(variables), ~client?, ~notifyOnNetworkStatusChange?, ~fetchPolicy=?fetchPolicy->Belt.Option.map(Types.fetchPolicyToJs), @@ -182,6 +190,7 @@ let useQuery: ~pollInterval?, ~context?, ~ssr?, + ~partialRefetch, (), ), ); @@ -203,35 +212,52 @@ let useQuery: networkStatus: ApolloClient_Types.toNetworkStatus(jsResult##networkStatus), refetch: (~variables=?, ()) => - jsResult##refetch(Js.Nullable.fromOption(variables)) + jsResult##refetch(Js.Nullable.fromOption(switch(variables) { + | Some(variables) => + Some(Operation.serializeVariables(variables)) + | None => None + })) |> Js.Promise.then_(result => Operation.parse( result.data->Js.Nullable.toOption->Belt.Option.getExn, ) |> Js.Promise.resolve ), - rawFetchMore: (~variables=?, ~updateQuery, ()) => - jsResult##fetchMore({Raw.variables, Raw.updateQuery}), - fetchMore: (~variables=?, ~updateQuery, ()) => { + rawFetchMore: (~variables=?, ~updateQuery=?, ()) => + jsResult##fetchMore({Raw.variables: variables, Raw.updateQuery}), + fetchMore: (~variables=?, ~updateQuery=?, ()) => { jsResult##fetchMore({ - Raw.variables, + Raw.variables: switch(variables) { + | Some (variables) => + Some(Operation.serializeVariables(variables)) + | None => None + }, Raw.updateQuery: - (previousResult, {fetchMoreResult, variables}) => { - let result = - updateQuery( - Operation.parse(previousResult), - { - fetchMoreResult: - switch (Js.Nullable.toOption(fetchMoreResult)) { - | None => None - | Some(fetchMoreResult) => - Some(Operation.parse(fetchMoreResult)) - }, - variables: Js.Nullable.toOption(variables), + switch (updateQuery) { + | Some(updateQuery) => + Some( + (previousResult, Raw.{fetchMoreResult, variables}) => { + let result = + updateQuery( + Operation.parse(previousResult), + ({ + fetchMoreResult: + switch (Js.Nullable.toOption(fetchMoreResult)) { + | None => None + | Some(fetchMoreResult) => + Some(Operation.parse(fetchMoreResult)) + }, + variables: + (Js.Nullable.toOption(variables): + option(Operation.Raw.t_variables)), + }: updateQueryOptions(Operation.t, + Operation.Raw.t_variables)), + ); + Operation.serialize(result); }, - ); - Operation.serialize(result); - }, + ) + | None => None + }, }); }, stopPolling: () => jsResult##stopPolling(), @@ -240,7 +266,12 @@ let useQuery: jsResult##subscribeToMore( subscribeToMoreOptionsJs( ~document, - ~variables?, + ~variables=?{switch(variables) { + | Some(variables) => + Some(Operation.serializeVariables(variables)) + | None => None + }} + , ~updateQuery?, (), ), @@ -251,7 +282,7 @@ let useQuery: }; let useQuery0: - type t t_variables raw_t raw_t_variables. + type t raw_t raw_t_variables t_variables. ( ~client: ApolloClient_Client.t=?, ~notifyOnNetworkStatusChange: bool=?, @@ -261,12 +292,14 @@ let useQuery0: ~pollInterval: int=?, ~context: Types.Context.t=?, ~ssr: bool=?, + ~partialRefetch: bool=?, (module Types.OperationNoRequiredVars with type t = t and type Raw.t = raw_t and - type Raw.t_variables = raw_t_variables) + type Raw.t_variables = raw_t_variables and + type t_variables = t_variables) ) => - queryResult(t, raw_t, raw_t_variables) = + queryResult(t, raw_t, t_variables, raw_t_variables) = ( ~client=?, ~notifyOnNetworkStatusChange=?, @@ -276,6 +309,7 @@ let useQuery0: ~pollInterval=?, ~context=?, ~ssr=?, + ~partialRefetch=?, (module Operation), ) => { useQuery( @@ -288,27 +322,30 @@ let useQuery0: ~pollInterval?, ~context?, ~ssr?, + ~partialRefetch?, (module Operation), ); }; let useQueryLegacy: - type t t_variables raw_t raw_t_variables. + type t raw_t raw_t_variables t_variables. ( ~client: ApolloClient_Client.t=?, - ~variables: raw_t_variables=?, + ~variables: t_variables=?, ~notifyOnNetworkStatusChange: bool=?, ~fetchPolicy: Types.fetchPolicy=?, ~errorPolicy: Types.errorPolicy=?, ~skip: bool=?, ~pollInterval: int=?, ~context: Types.Context.t=?, + ~partialRefetch: bool=?, (module Types.Operation with type t = t and type Raw.t = raw_t and - type Raw.t_variables = raw_t_variables) + type Raw.t_variables = raw_t_variables and + type t_variables = t_variables) ) => - (variant(t), queryResult(t, raw_t, raw_t_variables)) = + (variant(t), queryResult(t, raw_t, t_variables, raw_t_variables)) = ( ~client=?, ~variables=?, @@ -318,13 +355,17 @@ let useQueryLegacy: ~skip=?, ~pollInterval=?, ~context=?, + ~partialRefetch=?, (module Operation), ) => { let jsResult = useQueryJs( gql(. Operation.query), options( - ~variables?, + ~variables=?{switch(variables) { + | Some(variables) => Some(Operation.serializeVariables(variables)) + | None => None + }}, ~client?, ~notifyOnNetworkStatusChange?, ~fetchPolicy=?fetchPolicy->Belt.Option.map(Types.fetchPolicyToJs), @@ -332,6 +373,7 @@ let useQueryLegacy: ~skip?, ~pollInterval?, ~context?, + ~partialRefetch?, (), ), ); @@ -354,35 +396,49 @@ let useQueryLegacy: networkStatus: ApolloClient_Types.toNetworkStatus(jsResult##networkStatus), refetch: (~variables=?, ()) => - jsResult##refetch(Js.Nullable.fromOption(variables)) + jsResult##refetch(Js.Nullable.fromOption(switch(variables) { + | Some(variables) => + Some(Operation.serializeVariables(variables)) + | None => None + })) |> Js.Promise.then_(result => Operation.parse( result.data->Js.Nullable.toOption->Belt.Option.getExn, ) |> Js.Promise.resolve ), - rawFetchMore: (~variables=?, ~updateQuery, ()) => - jsResult##fetchMore({Raw.variables, Raw.updateQuery}), - fetchMore: (~variables=?, ~updateQuery, ()) => { + rawFetchMore: (~variables=?, ~updateQuery=?, ()) => + jsResult##fetchMore({Raw.variables: variables, Raw.updateQuery}), + fetchMore: (~variables=?, ~updateQuery=?, ()) => { jsResult##fetchMore({ - Raw.variables, + Raw.variables: switch(variables) { + | Some(variables) => + Some(Operation.serializeVariables(variables)) + | None => None + }, Raw.updateQuery: - (previousResult, {fetchMoreResult, variables}) => { - let result = - updateQuery( - Operation.parse(previousResult), - { - fetchMoreResult: - switch (Js.Nullable.toOption(fetchMoreResult)) { - | None => None - | Some(fetchMoreResult) => - Some(Operation.parse(fetchMoreResult)) - }, - variables: Js.Nullable.toOption(variables), + switch (updateQuery) { + | Some(updateQuery) => + Some( + (previousResult, {fetchMoreResult, variables}) => { + let result = + updateQuery( + Operation.parse(previousResult), + { + fetchMoreResult: + switch (Js.Nullable.toOption(fetchMoreResult)) { + | None => None + | Some(fetchMoreResult) => + Some(Operation.parse(fetchMoreResult)) + }, + variables: Js.Nullable.toOption(variables), + }, + ); + Operation.serialize(result); }, - ); - Operation.serialize(result); - }, + ) + | None => None + }, }); }, stopPolling: () => jsResult##stopPolling(), @@ -391,7 +447,11 @@ let useQueryLegacy: jsResult##subscribeToMore( subscribeToMoreOptionsJs( ~document, - ~variables?, + ~variables=?{switch(variables) { + | Some(variables) => + Some(Operation.serializeVariables(variables)) + | None => None + }}, ~updateQuery?, (), ), @@ -429,6 +489,7 @@ module Extend = (M: Types.Operation) => { ~pollInterval=?, ~context=?, ~ssr=?, + ~partialRefetch=?, variables, ) => { useQuery( @@ -441,6 +502,7 @@ module Extend = (M: Types.Operation) => { ~pollInterval?, ~context?, ~ssr?, + ~partialRefetch?, (module M), ); }; @@ -461,6 +523,7 @@ module ExtendNoRequiredVars = (M: Types.OperationNoRequiredVars) => { ~pollInterval=?, ~context=?, ~ssr=?, + ~partialRefetch=?, (), ) => { useQuery( @@ -477,6 +540,7 @@ module ExtendNoRequiredVars = (M: Types.OperationNoRequiredVars) => { ~pollInterval?, ~context?, ~ssr?, + ~partialRefetch?, (module M), ); }; diff --git a/src/ApolloClient_Subscription.re b/src/ApolloClient_Subscription.re index 60cc13d..4fc495f 100644 --- a/src/ApolloClient_Subscription.re +++ b/src/ApolloClient_Subscription.re @@ -43,12 +43,13 @@ external useSubscription: let useSubscription: type t t_variables raw_t raw_t_variables. ( - ~variables: Js.Json.t=?, + ~variables: t_variables=?, ~client: ApolloClient_Client.t=?, ~skip: bool=?, (module Types.Operation with type t = t and type Raw.t = raw_t and + type t_variables = t_variables and type Raw.t_variables = raw_t_variables) ) => (variant(t), result(t)) = @@ -56,7 +57,9 @@ let useSubscription: let jsResult = useSubscription( gql(. Operation.query), - options(~variables?, ~client?, ~skip?, ()), + options(~variables=?{switch(variables) { + | Some(variables) => Some(Operation.serializeVariables(variables)) + | None => None }}, ~client?, ~skip?, ()), ); let result = { diff --git a/src/ApolloClient_Types.re b/src/ApolloClient_Types.re index 9f3e0b5..b022690 100644 --- a/src/ApolloClient_Types.re +++ b/src/ApolloClient_Types.re @@ -63,7 +63,7 @@ type graphqlError = { nodes: Js.Nullable.t(array(string)), }; -type executionResult('raw_t) = { +type rawExecutionResult('raw_t) = { errors: Js.Nullable.t(Js.Array.t(graphqlError)), data: Js.Nullable.t('raw_t), }; @@ -85,7 +85,7 @@ type operation('raw_t_variables) = { type errorResponse('raw_t, 'raw_t_variables) = { graphQLErrors: Js.Nullable.t(Js.Array.t(graphqlError)), networkError: Js.Nullable.t(networkError), - response: Js.Nullable.t(executionResult('raw_t)), + response: Js.Nullable.t(rawExecutionResult('raw_t)), operation: operation('raw_t_variables), forward: operation('raw_t_variables) => Observable.subscription, }; @@ -195,12 +195,14 @@ module type Operation = { type t_variables; }; type t; + type t_variables; let parse: Raw.t => t; let serialize: t => Raw.t; + let serializeVariables: t_variables => Raw.t_variables; }; module type OperationNoRequiredVars = { include Operation; - let makeDefaultVariables: unit => Raw.t_variables; + let makeDefaultVariables: unit => t_variables; }; From f8259d852460f01bd9df76896b381a33904835e9 Mon Sep 17 00:00:00 2001 From: Jaap Frolich Date: Tue, 11 Aug 2020 17:45:14 +0800 Subject: [PATCH 13/13] reformat --- src/ApolloClient_Query.re | 82 ++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/src/ApolloClient_Query.re b/src/ApolloClient_Query.re index 679e832..9acbbe5 100644 --- a/src/ApolloClient_Query.re +++ b/src/ApolloClient_Query.re @@ -212,11 +212,15 @@ let useQuery: networkStatus: ApolloClient_Types.toNetworkStatus(jsResult##networkStatus), refetch: (~variables=?, ()) => - jsResult##refetch(Js.Nullable.fromOption(switch(variables) { - | Some(variables) => - Some(Operation.serializeVariables(variables)) - | None => None - })) + jsResult##refetch( + Js.Nullable.fromOption( + switch (variables) { + | Some(variables) => + Some(Operation.serializeVariables(variables)) + | None => None + }, + ), + ) |> Js.Promise.then_(result => Operation.parse( result.data->Js.Nullable.toOption->Belt.Option.getExn, @@ -224,14 +228,15 @@ let useQuery: |> Js.Promise.resolve ), rawFetchMore: (~variables=?, ~updateQuery=?, ()) => - jsResult##fetchMore({Raw.variables: variables, Raw.updateQuery}), + jsResult##fetchMore({Raw.variables, Raw.updateQuery}), fetchMore: (~variables=?, ~updateQuery=?, ()) => { jsResult##fetchMore({ - Raw.variables: switch(variables) { - | Some (variables) => + Raw.variables: + switch (variables) { + | Some(variables) => Some(Operation.serializeVariables(variables)) | None => None - }, + }, Raw.updateQuery: switch (updateQuery) { | Some(updateQuery) => @@ -240,18 +245,22 @@ let useQuery: let result = updateQuery( Operation.parse(previousResult), - ({ + { fetchMoreResult: switch (Js.Nullable.toOption(fetchMoreResult)) { | None => None | Some(fetchMoreResult) => Some(Operation.parse(fetchMoreResult)) }, - variables: - (Js.Nullable.toOption(variables): - option(Operation.Raw.t_variables)), - }: updateQueryOptions(Operation.t, - Operation.Raw.t_variables)), + variables: ( + Js.Nullable.toOption(variables): + option(Operation.Raw.t_variables) + ), + }: + updateQueryOptions( + Operation.t, + Operation.Raw.t_variables, + ), ); Operation.serialize(result); }, @@ -266,12 +275,13 @@ let useQuery: jsResult##subscribeToMore( subscribeToMoreOptionsJs( ~document, - ~variables=?{switch(variables) { + ~variables=?{ + switch (variables) { | Some(variables) => Some(Operation.serializeVariables(variables)) | None => None - }} - , + }; + }, ~updateQuery?, (), ), @@ -362,10 +372,13 @@ let useQueryLegacy: useQueryJs( gql(. Operation.query), options( - ~variables=?{switch(variables) { - | Some(variables) => Some(Operation.serializeVariables(variables)) + ~variables=?{ + switch (variables) { + | Some(variables) => + Some(Operation.serializeVariables(variables)) | None => None - }}, + }; + }, ~client?, ~notifyOnNetworkStatusChange?, ~fetchPolicy=?fetchPolicy->Belt.Option.map(Types.fetchPolicyToJs), @@ -396,11 +409,15 @@ let useQueryLegacy: networkStatus: ApolloClient_Types.toNetworkStatus(jsResult##networkStatus), refetch: (~variables=?, ()) => - jsResult##refetch(Js.Nullable.fromOption(switch(variables) { - | Some(variables) => - Some(Operation.serializeVariables(variables)) - | None => None - })) + jsResult##refetch( + Js.Nullable.fromOption( + switch (variables) { + | Some(variables) => + Some(Operation.serializeVariables(variables)) + | None => None + }, + ), + ) |> Js.Promise.then_(result => Operation.parse( result.data->Js.Nullable.toOption->Belt.Option.getExn, @@ -408,14 +425,15 @@ let useQueryLegacy: |> Js.Promise.resolve ), rawFetchMore: (~variables=?, ~updateQuery=?, ()) => - jsResult##fetchMore({Raw.variables: variables, Raw.updateQuery}), + jsResult##fetchMore({Raw.variables, Raw.updateQuery}), fetchMore: (~variables=?, ~updateQuery=?, ()) => { jsResult##fetchMore({ - Raw.variables: switch(variables) { + Raw.variables: + switch (variables) { | Some(variables) => Some(Operation.serializeVariables(variables)) | None => None - }, + }, Raw.updateQuery: switch (updateQuery) { | Some(updateQuery) => @@ -447,11 +465,13 @@ let useQueryLegacy: jsResult##subscribeToMore( subscribeToMoreOptionsJs( ~document, - ~variables=?{switch(variables) { + ~variables=?{ + switch (variables) { | Some(variables) => Some(Operation.serializeVariables(variables)) | None => None - }}, + }; + }, ~updateQuery?, (), ),