From 0204b183dac69f9f38bef5b2e82d4f43e0e7b800 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sat, 9 May 2020 20:23:30 -0500 Subject: [PATCH 01/21] refactor: apollo client 3 mirroring exploration --- src/Apollo_Client/Apollo_Client.re | 44 +++++ .../Apollo_Client__ApolloClient.re | 1 + src/Apollo_Client/Apollo_Client__Types.re | 9 + src/Apollo_Client/Apollo_Client__Utils.re | 11 ++ .../graphql-tag/Apollo_Client__GraphqlTag.re | 3 + .../graphql/Apollo_Client__Graphql.re | 6 + .../error/Apollo_Client__Graphql_Error.re | 1 + ...ollo_Client__Graphql_Error_GraphQLError.re | 8 + .../Apollo_Client__Graphql_Language.re | 1 + .../Apollo_Client__Graphql_Location.re | 4 + src/Apollo_Client/core/Apollo_Client__Core.re | 3 + .../core/Apollo_Client__Core_NetworkStatus.re | 20 ++ .../core/Apollo_Client__Core_Types.re | 27 +++ .../Apollo_Client__Core_WatchQueryOptions.re | 32 ++++ .../errors/Apollo_Client__Errors.re | 16 ++ .../react/Apollo_Client__React.re | 2 + .../hooks/Apollo_Client__React_UseQuery.re | 103 +++++++++++ .../react/types/Apollo_Client__React_Types.re | 171 ++++++++++++++++++ 18 files changed, 462 insertions(+) create mode 100644 src/Apollo_Client/Apollo_Client.re create mode 100644 src/Apollo_Client/Apollo_Client__ApolloClient.re create mode 100644 src/Apollo_Client/Apollo_Client__Types.re create mode 100644 src/Apollo_Client/Apollo_Client__Utils.re create mode 100644 src/Apollo_Client/_dependencies/graphql-tag/Apollo_Client__GraphqlTag.re create mode 100644 src/Apollo_Client/_peerDependencies/graphql/Apollo_Client__Graphql.re create mode 100644 src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error.re create mode 100644 src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re create mode 100644 src/Apollo_Client/_peerDependencies/graphql/language/Apollo_Client__Graphql_Language.re create mode 100644 src/Apollo_Client/_peerDependencies/graphql/location/Apollo_Client__Graphql_Location.re create mode 100644 src/Apollo_Client/core/Apollo_Client__Core.re create mode 100644 src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re create mode 100644 src/Apollo_Client/core/Apollo_Client__Core_Types.re create mode 100644 src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re create mode 100644 src/Apollo_Client/errors/Apollo_Client__Errors.re create mode 100644 src/Apollo_Client/react/Apollo_Client__React.re create mode 100644 src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re create mode 100644 src/Apollo_Client/react/types/Apollo_Client__React_Types.re diff --git a/src/Apollo_Client/Apollo_Client.re b/src/Apollo_Client/Apollo_Client.re new file mode 100644 index 0000000..821426a --- /dev/null +++ b/src/Apollo_Client/Apollo_Client.re @@ -0,0 +1,44 @@ +// export { default as Observable } from 'zen-observable'; +// export { isReference, makeReference } from './utilities/graphql/storeUtils.js'; +// export { ApolloLink } from './link/core/ApolloLink.js'; +// export { execute } from './link/core/execute.js'; +// export { ApolloError, isApolloError } from './errors/ApolloError.js'; +// export { NetworkStatus } from './core/networkStatus.js'; +// export { FetchType } from './core/types.js'; +// export { ObservableQuery } from './core/ObservableQuery.js'; +// export { serializeFetchParameter } from './link/http/serializeFetchParameter.js'; +// export { selectURI } from './link/http/selectURI.js'; +// export { throwServerError } from './link/utils/throwServerError.js'; +// export { parseAndCheckHttpResponse } from './link/http/parseAndCheckHttpResponse.js'; +// export { checkFetcher } from './link/http/checkFetcher.js'; +// export { fallbackHttpConfig, selectHttpOptionsAndBody } from './link/http/selectHttpOptionsAndBody.js'; +// export { createSignalIfSupported } from './link/http/createSignalIfSupported.js'; +// export { fromError } from './link/utils/fromError.js'; +// export { createHttpLink } from './link/http/createHttpLink.js'; +// export { HttpLink } from './link/http/HttpLink.js'; +// export { ApolloClient } from './ApolloClient.js'; +// export { ApolloCache } from './cache/core/cache.js'; +// export { Cache } from './cache/core/types/Cache.js'; +// export { MissingFieldError } from './cache/core/types/common.js'; +// export { defaultDataIdFromObject } from './cache/inmemory/policies.js'; +// export { InMemoryCache } from './cache/inmemory/inMemoryCache.js'; +// export { empty } from './link/core/empty.js'; +// export { from } from './link/core/from.js'; +// export { split } from './link/core/split.js'; +// export { concat } from './link/core/concat.js'; +// export { toPromise } from './link/utils/toPromise.js'; +// export { fromPromise } from './link/utils/fromPromise.js'; +// export { disableExperimentalFragmentVariables, disableFragmentWarnings, enableExperimentalFragmentVariables, resetCaches } from './core/index.js'; +// export { getApolloContext, resetApolloContext } from './react/context/ApolloContext.js'; +// export { ApolloProvider } from './react/context/ApolloProvider.js'; +// export { ApolloConsumer } from './react/context/ApolloConsumer.js'; +// export { DocumentType, operationName, parser } from './react/parser/parser.js'; +// export { useLazyQuery } from './react/hooks/useLazyQuery.js'; +// export { useMutation } from './react/hooks/useMutation.js'; +// export { useSubscription } from './react/hooks/useSubscription.js'; +// export { useApolloClient } from './react/hooks/useApolloClient.js'; +// export { RenderPromises } from './react/ssr/RenderPromises.js'; + +let useQuery = Apollo_Client__React_UseQuery.useQuery; + +let gql = Apollo_Client__GraphqlTag.gql; diff --git a/src/Apollo_Client/Apollo_Client__ApolloClient.re b/src/Apollo_Client/Apollo_Client__ApolloClient.re new file mode 100644 index 0000000..1896441 --- /dev/null +++ b/src/Apollo_Client/Apollo_Client__ApolloClient.re @@ -0,0 +1 @@ +type t; diff --git a/src/Apollo_Client/Apollo_Client__Types.re b/src/Apollo_Client/Apollo_Client__Types.re new file mode 100644 index 0000000..041fe6f --- /dev/null +++ b/src/Apollo_Client/Apollo_Client__Types.re @@ -0,0 +1,9 @@ +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), +); diff --git a/src/Apollo_Client/Apollo_Client__Utils.re b/src/Apollo_Client/Apollo_Client__Utils.re new file mode 100644 index 0000000..ee9553b --- /dev/null +++ b/src/Apollo_Client/Apollo_Client__Utils.re @@ -0,0 +1,11 @@ +let useGuaranteedMemo1 = (f, dependency) => { + let value = React.useRef(f()); + let previousDependency = React.useRef(dependency); + + if (dependency !== previousDependency->React.Ref.current) { + value->React.Ref.setCurrent(f()); + previousDependency->React.Ref.setCurrent(dependency); + }; + + value->React.Ref.current; +}; diff --git a/src/Apollo_Client/_dependencies/graphql-tag/Apollo_Client__GraphqlTag.re b/src/Apollo_Client/_dependencies/graphql-tag/Apollo_Client__GraphqlTag.re new file mode 100644 index 0000000..1d59482 --- /dev/null +++ b/src/Apollo_Client/_dependencies/graphql-tag/Apollo_Client__GraphqlTag.re @@ -0,0 +1,3 @@ +[@bs.module "graphql-tag"] +external gql: string => Apollo_Client__Graphql_Language.documentNode = + "default"; diff --git a/src/Apollo_Client/_peerDependencies/graphql/Apollo_Client__Graphql.re b/src/Apollo_Client/_peerDependencies/graphql/Apollo_Client__Graphql.re new file mode 100644 index 0000000..fb9b8d9 --- /dev/null +++ b/src/Apollo_Client/_peerDependencies/graphql/Apollo_Client__Graphql.re @@ -0,0 +1,6 @@ +module Error = Apollo_Client__Graphql_Error; +module GraphQLError = Apollo_Client__Graphql_Error_GraphQLError; +module Language = Apollo_Client__Graphql_Language; +module Location = Apollo_Client__Graphql_Location; + +type documentNode; diff --git a/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error.re b/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error.re new file mode 100644 index 0000000..a88f2a6 --- /dev/null +++ b/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error.re @@ -0,0 +1 @@ +module GraphQLError = Apollo_Client__Graphql_Error_GraphQLError; diff --git a/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re b/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re new file mode 100644 index 0000000..27f7b16 --- /dev/null +++ b/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re @@ -0,0 +1,8 @@ +module Graphql_Location = Apollo_Client__Graphql_Location; + +type t = { + message: string, + locations: Js.nullable(array(Graphql_Location.sourceLocation)), + // Union? https://bucklescript.github.io/blog/2020/02/07/union-types-in-bucklescript + path: Js.nullable(array(string)) // ACTUAL: string | number +}; diff --git a/src/Apollo_Client/_peerDependencies/graphql/language/Apollo_Client__Graphql_Language.re b/src/Apollo_Client/_peerDependencies/graphql/language/Apollo_Client__Graphql_Language.re new file mode 100644 index 0000000..5bdad1d --- /dev/null +++ b/src/Apollo_Client/_peerDependencies/graphql/language/Apollo_Client__Graphql_Language.re @@ -0,0 +1 @@ +type documentNode; diff --git a/src/Apollo_Client/_peerDependencies/graphql/location/Apollo_Client__Graphql_Location.re b/src/Apollo_Client/_peerDependencies/graphql/location/Apollo_Client__Graphql_Location.re new file mode 100644 index 0000000..bb1509b --- /dev/null +++ b/src/Apollo_Client/_peerDependencies/graphql/location/Apollo_Client__Graphql_Location.re @@ -0,0 +1,4 @@ +type sourceLocation = { + line: int, + column: int, +}; diff --git a/src/Apollo_Client/core/Apollo_Client__Core.re b/src/Apollo_Client/core/Apollo_Client__Core.re new file mode 100644 index 0000000..c5020ae --- /dev/null +++ b/src/Apollo_Client/core/Apollo_Client__Core.re @@ -0,0 +1,3 @@ +module NetworkStatus = Apollo_Client__Core_NetworkStatus; +module Types = Apollo_Client__Core_Types; +module WatchQueryOptions = Apollo_Client__Core_WatchQueryOptions; diff --git a/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re b/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re new file mode 100644 index 0000000..2c8eb2a --- /dev/null +++ b/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re @@ -0,0 +1,20 @@ +type t = + | Loading + | SetVariables + | FetchMore + | Refetch + | Poll + | Ready + | Error + | Unknown; + +let fromRaw = + fun + | 1 => Loading + | 2 => SetVariables + | 3 => FetchMore + | 4 => Refetch + | 6 => Poll + | 7 => Ready + | 8 => Error + | _ => Unknown; diff --git a/src/Apollo_Client/core/Apollo_Client__Core_Types.re b/src/Apollo_Client/core/Apollo_Client__Core_Types.re new file mode 100644 index 0000000..f97040f --- /dev/null +++ b/src/Apollo_Client/core/Apollo_Client__Core_Types.re @@ -0,0 +1,27 @@ +module Graphql = Apollo_Client__Graphql; + +module ApolloQueryResult = { + module Raw = { + type t('raw_tData) = { + data: Js.nullable('raw_tData), + errors: Js.nullable(array(Graphql.Error.GraphQLError.t)), + loading: bool, + networkStatus: int, + }; + }; + + type t('tData) = { + data: option('tData), + errors: option(array(Graphql.Error.GraphQLError.t)), + loading: bool, + networkStatus: int, + }; + + let fromRaw = + ({data, errors, loading, networkStatus}: Raw.t('raw_tData), ~parse) => { + data: data->Js.toOption->Belt.Option.map(parse), + errors: errors->Js.toOption, + loading, + networkStatus, + }; +}; diff --git a/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re b/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re new file mode 100644 index 0000000..21f03df --- /dev/null +++ b/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re @@ -0,0 +1,32 @@ +module ErrorPolicy = { + type t = + | None + | Ignore + | All; + + let toRaw = + fun + | None => "none" + | Ignore => "ignore" + | All => "all"; +}; + +module WatchQueryFetchPolicy = { + type t = + | CacheAndNetwork + // ...extends FetchPolicy + | CacheFirst + | NetworkOnly + | CacheOnly + | NoCache + | Standby; + + let toRaw = + fun + | CacheFirst => "cache-first" + | CacheAndNetwork => "cache-and-network" + | NetworkOnly => "network-only" + | CacheOnly => "cache-only" + | NoCache => "no-cache" + | Standby => "standby"; +}; diff --git a/src/Apollo_Client/errors/Apollo_Client__Errors.re b/src/Apollo_Client/errors/Apollo_Client__Errors.re new file mode 100644 index 0000000..00f6da5 --- /dev/null +++ b/src/Apollo_Client/errors/Apollo_Client__Errors.re @@ -0,0 +1,16 @@ +module Graphql = Apollo_Client__Graphql; + +module ApolloError = { + type t = { + extraInfo: Js.Json.t, + graphQLErrors: array(Graphql.Error.GraphQLError.t), + networkError: Js.nullable(Js.Exn.t), + // ...extends Error + name: string, + message: string, + stack: option(string), + }; + // type errorOptions ={ graphQLErrors, networkError, errorMessage, extraInfo}; + // [@bs.new] [@bs.module "@apollo/client"] + // external make: errorOptions => t = "ApolloError"; +}; diff --git a/src/Apollo_Client/react/Apollo_Client__React.re b/src/Apollo_Client/react/Apollo_Client__React.re new file mode 100644 index 0000000..5c3061e --- /dev/null +++ b/src/Apollo_Client/react/Apollo_Client__React.re @@ -0,0 +1,2 @@ +module Types = Apollo_Client__React_Types; +let useQuery = Apollo_Client__React_UseQuery.useQuery; diff --git a/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re b/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re new file mode 100644 index 0000000..df9dad6 --- /dev/null +++ b/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re @@ -0,0 +1,103 @@ +module Core = Apollo_Client__Core; +module Errors = Apollo_Client__Errors; +module Graphql = Apollo_Client__Graphql; +module GraphqlTag = Apollo_Client__GraphqlTag; +module React_Types = Apollo_Client__React_Types; + +type simpleQueryResult('a) = + | Data('a) + | Error(Errors.ApolloError.t) + | Loading + | NoData; + +module Raw = { + [@bs.module "@apollo/client"] + external useQuery: + ( + ~query: Graphql.Language.documentNode, + ~options: React_Types.QueryHookOptions.t('raw_tData, 'raw_tVariables)=? + ) => + React_Types.QueryResult.Raw.t('raw_tData, 'raw_tVariables) = + "useQuery"; +}; + +let useQuery: + ( + ~client: Apollo_Client__ApolloClient.t=?, + ~context: Js.Json.t=?, + ~displayName: string=?, + ~errorPolicy: Core.WatchQueryOptions.ErrorPolicy.t=?, + ~fetchPolicy: Core.WatchQueryOptions.WatchQueryFetchPolicy.t=?, + ~notifyOnNetworkStatusChange: bool=?, + ~onCompleted: 'raw_tData => unit=?, + ~onError: Errors.ApolloError.t => unit=?, + ~partialRefetch: bool=?, + ~pollInterval: int=?, + ~skip: bool=?, + ~ssr: bool=?, + ~variables: 'raw_tVariables=?, + Apollo_Client__Types.graphqlDefinition('tData, 'raw_tData) + ) => + ( + simpleQueryResult('tData), + React_Types.QueryResult.t('tData, 'raw_tVariables), + ) = + ( + ~client=?, + ~context=?, + ~displayName=?, + ~errorPolicy=?, + ~fetchPolicy=?, + ~notifyOnNetworkStatusChange=?, + ~onCompleted=?, + ~onError=?, + ~partialRefetch=?, + ~pollInterval=?, + ~skip=?, + ~ssr=?, + ~variables=?, + (parse, query, serialize), + ) => { + let jsQueryResult = + Raw.useQuery( + ~query=GraphqlTag.gql(query), + ~options={ + client, + context, + displayName, + errorPolicy, + fetchPolicy, + onCompleted, + onError, + notifyOnNetworkStatusChange, + partialRefetch, + pollInterval, + query: None, + skip, + ssr, + variables, + }, + ); + + Apollo_Client__Utils.useGuaranteedMemo1( + () => { + let queryResult = + jsQueryResult->React_Types.QueryResult.fromRaw(~parse, ~serialize); + + let simple = + Apollo_Client__Utils.useGuaranteedMemo1( + () => + switch (queryResult) { + | {loading: true} => Loading + | {error: Some(error)} => Error(error) + | {data: Some(data)} => Data(data) + | _ => NoData + }, + [|queryResult|], + ); + + (simple, queryResult); + }, + jsQueryResult, + ); + }; diff --git a/src/Apollo_Client/react/types/Apollo_Client__React_Types.re b/src/Apollo_Client/react/types/Apollo_Client__React_Types.re new file mode 100644 index 0000000..bbc9429 --- /dev/null +++ b/src/Apollo_Client/react/types/Apollo_Client__React_Types.re @@ -0,0 +1,171 @@ +module Core = Apollo_Client__Core; +module Errors = Apollo_Client__Errors; +module Graphql = Apollo_Client__Graphql; + +module QueryHookOptions = { + module Raw = { + type t('raw_tData, 'raw_tVariables) = { + query: option(Graphql.documentNode), + // ...extends QueryFunctionOptions + displayName: option(string), + skip: option(bool), + onCompleted: option('raw_tData => unit), + onError: option(Errors.ApolloError.t => unit), + // ..extends BaseQueryOptions + client: option(Apollo_Client__ApolloClient.t), + context: option(Js.Json.t), // ACTUAL: Record + errorPolicy: option(string), + fetchPolicy: option(string), + notifyOnNetworkStatusChange: option(bool), + pollInterval: option(int), + ssr: option(bool), + variables: option('raw_tVariables), + partialRefetch: option(bool), + // INTENTIONALLY IGNORED + // returnPartialData: option(bool), + }; + }; + + type t('raw_tData, 'raw_tVariables) = { + query: option(Graphql.documentNode), + // ...extends QueryFunctionOptions + displayName: option(string), + skip: option(bool), + // consider parsing? + onCompleted: option('raw_tData => unit), + onError: option(Errors.ApolloError.t => unit), + // ...extends BaseQueryOptions + client: option(Apollo_Client__ApolloClient.t), + context: option(Js.Json.t), + errorPolicy: option(Core.WatchQueryOptions.ErrorPolicy.t), + fetchPolicy: option(Core.WatchQueryOptions.WatchQueryFetchPolicy.t), + notifyOnNetworkStatusChange: option(bool), + partialRefetch: option(bool), + pollInterval: option(int), + // INTENTIONALLY IGNORED + // returnPartialData: option(bool), + ssr: option(bool), + variables: option('raw_tVariables), + }; + + let toRaw = (t: t(_, _)): Raw.t(_, _) => { + client: t.client, + context: t.context, + displayName: t.displayName, + errorPolicy: + t.errorPolicy + ->Belt.Option.map(Core.WatchQueryOptions.ErrorPolicy.toRaw), + onCompleted: t.onCompleted, + onError: t.onError, + fetchPolicy: + t.fetchPolicy + ->Belt.Option.map(Core.WatchQueryOptions.WatchQueryFetchPolicy.toRaw), + notifyOnNetworkStatusChange: t.notifyOnNetworkStatusChange, + query: t.query, + pollInterval: t.pollInterval, + partialRefetch: t.partialRefetch, + skip: t.skip, + ssr: t.ssr, + variables: t.variables, + }; +}; + +module QueryResult = { + module Raw = { + type t_fetchMoreOptions_updateQueryOptions('tData, 'raw_tVariables) = { + fetchMoreResult: Js.nullable('tData), + variables: Js.nullable('raw_tVariables), + }; + + type t_fetchMoreOptions('raw_tData, 'raw_tVariables) = { + query: option(Graphql.Language.documentNode), + variables: option('raw_tVariables), + context: option(Js.Json.t), + updateQuery: + ( + 'raw_tData, + t_fetchMoreOptions_updateQueryOptions('raw_tData, 'raw_tVariables) + ) => + 'raw_tData, + }; + + type t('raw_tData, 'raw_tVariables) = { + fetchMore: + t_fetchMoreOptions('raw_tData, 'raw_tVariables) => + Js.Promise.t(Core.Types.ApolloQueryResult.Raw.t('raw_tData)), + called: bool, + client: Apollo_Client__ApolloClient.t, + data: Js.nullable('raw_tData), + error: Js.nullable(Errors.ApolloError.t), + loading: bool, + networkStatus: Core.NetworkStatus.t, + }; + }; + + type t_updateQueryOptions('tData, 'raw_tVariables) = { + fetchMoreResult: option('tData), + variables: option('raw_tVariables), + }; + + type t('tData, 'raw_tVariables) = { + called: bool, + client: Apollo_Client__ApolloClient.t, + data: option('tData), + error: option(Errors.ApolloError.t), + fetchMore: + ( + ~context: Js.Json.t=?, + ~variables: 'raw_tVariables=?, + ~updateQuery: ( + 'tData, + t_updateQueryOptions('tData, 'raw_tVariables) + ) => + 'tData, + unit + ) => + Js.Promise.t(Core.Types.ApolloQueryResult.t('tData)), + loading: bool, + networkStatus: Core.NetworkStatus.t, + }; + + let fromRaw: + ( + Raw.t('raw_tData, 'raw_tVariables), + ~parse: 'raw_tData => 'tData, + ~serialize: 'tData => 'raw_tData + ) => + t('tData, 'raw_tVariables) = + (raw, ~parse, ~serialize) => { + called: raw.called, + client: raw.client, + data: raw.data->Js.toOption->Belt.Option.map(parse), + error: raw.error->Js.toOption, + fetchMore: + (~context=?, ~variables=?, ~updateQuery as jsUpdateQuery, ()) => { + raw.fetchMore({ + context, + query: None, + updateQuery: (previousResult, {fetchMoreResult, variables}) => + jsUpdateQuery( + parse(previousResult), + { + fetchMoreResult: + fetchMoreResult->Js.toOption->Belt.Option.map(parse), + variables: variables->Js.toOption, + }, + ) + ->serialize, + variables, + }) + ->Js.Promise.then_( + jsResult => + Js.Promise.resolve( + Core.Types.ApolloQueryResult.fromRaw(jsResult, ~parse), + ), + _, + ); + }, + loading: raw.loading, + networkStatus: raw.networkStatus, + }; +}; From 09316543419a876f3298d7b61811ec708e7e6ee8 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sun, 10 May 2020 09:20:39 -0500 Subject: [PATCH 02/21] fix: bad copy/paste --- .../react/hooks/Apollo_Client__React_UseQuery.re | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re b/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re index df9dad6..cee297e 100644 --- a/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re +++ b/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re @@ -85,16 +85,12 @@ let useQuery: jsQueryResult->React_Types.QueryResult.fromRaw(~parse, ~serialize); let simple = - Apollo_Client__Utils.useGuaranteedMemo1( - () => - switch (queryResult) { - | {loading: true} => Loading - | {error: Some(error)} => Error(error) - | {data: Some(data)} => Data(data) - | _ => NoData - }, - [|queryResult|], - ); + switch (queryResult) { + | {loading: true} => Loading + | {error: Some(error)} => Error(error) + | {data: Some(data)} => Data(data) + | _ => NoData + }; (simple, queryResult); }, From d2e7695cd49a062e7b29dca085411cfd122aca7a Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Mon, 18 May 2020 07:09:39 -0500 Subject: [PATCH 03/21] refactor: rename `raw` stuff to `js` --- .../core/Apollo_Client__Core_NetworkStatus.re | 2 +- .../core/Apollo_Client__Core_Types.re | 14 ++-- .../Apollo_Client__Core_WatchQueryOptions.re | 4 +- .../hooks/Apollo_Client__React_UseQuery.re | 20 ++--- .../react/types/Apollo_Client__React_Types.re | 79 +++++++++---------- 5 files changed, 59 insertions(+), 60 deletions(-) diff --git a/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re b/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re index 2c8eb2a..ffd6be8 100644 --- a/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re +++ b/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re @@ -8,7 +8,7 @@ type t = | Error | Unknown; -let fromRaw = +let fromJs = fun | 1 => Loading | 2 => SetVariables diff --git a/src/Apollo_Client/core/Apollo_Client__Core_Types.re b/src/Apollo_Client/core/Apollo_Client__Core_Types.re index f97040f..0803e76 100644 --- a/src/Apollo_Client/core/Apollo_Client__Core_Types.re +++ b/src/Apollo_Client/core/Apollo_Client__Core_Types.re @@ -1,24 +1,24 @@ module Graphql = Apollo_Client__Graphql; module ApolloQueryResult = { - module Raw = { - type t('raw_tData) = { - data: Js.nullable('raw_tData), + module JS = { + type t('jsData) = { + data: Js.nullable('jsData), errors: Js.nullable(array(Graphql.Error.GraphQLError.t)), loading: bool, networkStatus: int, }; }; - type t('tData) = { - data: option('tData), + type t('parsedData) = { + data: option('parsedData), errors: option(array(Graphql.Error.GraphQLError.t)), loading: bool, networkStatus: int, }; - let fromRaw = - ({data, errors, loading, networkStatus}: Raw.t('raw_tData), ~parse) => { + let fromJs = + ({data, errors, loading, networkStatus}: JS.t('jsData), ~parse) => { data: data->Js.toOption->Belt.Option.map(parse), errors: errors->Js.toOption, loading, diff --git a/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re b/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re index 21f03df..dff7c30 100644 --- a/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re +++ b/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re @@ -4,7 +4,7 @@ module ErrorPolicy = { | Ignore | All; - let toRaw = + let toJs = fun | None => "none" | Ignore => "ignore" @@ -21,7 +21,7 @@ module WatchQueryFetchPolicy = { | NoCache | Standby; - let toRaw = + let toJs = fun | CacheFirst => "cache-first" | CacheAndNetwork => "cache-and-network" diff --git a/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re b/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re index cee297e..12e2162 100644 --- a/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re +++ b/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re @@ -10,14 +10,14 @@ type simpleQueryResult('a) = | Loading | NoData; -module Raw = { +module JS = { [@bs.module "@apollo/client"] external useQuery: ( ~query: Graphql.Language.documentNode, - ~options: React_Types.QueryHookOptions.t('raw_tData, 'raw_tVariables)=? + ~options: React_Types.QueryHookOptions.t('jsData, 'variables)=? ) => - React_Types.QueryResult.Raw.t('raw_tData, 'raw_tVariables) = + React_Types.QueryResult.JS.t('jsData, 'variables) = "useQuery"; }; @@ -29,18 +29,18 @@ let useQuery: ~errorPolicy: Core.WatchQueryOptions.ErrorPolicy.t=?, ~fetchPolicy: Core.WatchQueryOptions.WatchQueryFetchPolicy.t=?, ~notifyOnNetworkStatusChange: bool=?, - ~onCompleted: 'raw_tData => unit=?, + ~onCompleted: 'jsData => unit=?, ~onError: Errors.ApolloError.t => unit=?, ~partialRefetch: bool=?, ~pollInterval: int=?, ~skip: bool=?, ~ssr: bool=?, - ~variables: 'raw_tVariables=?, - Apollo_Client__Types.graphqlDefinition('tData, 'raw_tData) + ~variables: 'variables=?, + Apollo_Client__Types.graphqlDefinition('parsedData, 'jsData) ) => ( - simpleQueryResult('tData), - React_Types.QueryResult.t('tData, 'raw_tVariables), + simpleQueryResult('parsedData), + React_Types.QueryResult.t('parsedData, 'variables), ) = ( ~client=?, @@ -59,7 +59,7 @@ let useQuery: (parse, query, serialize), ) => { let jsQueryResult = - Raw.useQuery( + JS.useQuery( ~query=GraphqlTag.gql(query), ~options={ client, @@ -82,7 +82,7 @@ let useQuery: Apollo_Client__Utils.useGuaranteedMemo1( () => { let queryResult = - jsQueryResult->React_Types.QueryResult.fromRaw(~parse, ~serialize); + jsQueryResult->React_Types.QueryResult.fromJs(~parse, ~serialize); let simple = switch (queryResult) { diff --git a/src/Apollo_Client/react/types/Apollo_Client__React_Types.re b/src/Apollo_Client/react/types/Apollo_Client__React_Types.re index bbc9429..0bab3c6 100644 --- a/src/Apollo_Client/react/types/Apollo_Client__React_Types.re +++ b/src/Apollo_Client/react/types/Apollo_Client__React_Types.re @@ -3,13 +3,13 @@ module Errors = Apollo_Client__Errors; module Graphql = Apollo_Client__Graphql; module QueryHookOptions = { - module Raw = { - type t('raw_tData, 'raw_tVariables) = { + module JS = { + type t('jsData, 'variables) = { query: option(Graphql.documentNode), // ...extends QueryFunctionOptions displayName: option(string), skip: option(bool), - onCompleted: option('raw_tData => unit), + onCompleted: option('jsData => unit), onError: option(Errors.ApolloError.t => unit), // ..extends BaseQueryOptions client: option(Apollo_Client__ApolloClient.t), @@ -19,20 +19,20 @@ module QueryHookOptions = { notifyOnNetworkStatusChange: option(bool), pollInterval: option(int), ssr: option(bool), - variables: option('raw_tVariables), + variables: option('variables), partialRefetch: option(bool), // INTENTIONALLY IGNORED // returnPartialData: option(bool), }; }; - type t('raw_tData, 'raw_tVariables) = { + type t('jsData, 'variables) = { query: option(Graphql.documentNode), // ...extends QueryFunctionOptions displayName: option(string), skip: option(bool), // consider parsing? - onCompleted: option('raw_tData => unit), + onCompleted: option('jsData => unit), onError: option(Errors.ApolloError.t => unit), // ...extends BaseQueryOptions client: option(Apollo_Client__ApolloClient.t), @@ -45,21 +45,20 @@ module QueryHookOptions = { // INTENTIONALLY IGNORED // returnPartialData: option(bool), ssr: option(bool), - variables: option('raw_tVariables), + variables: option('variables), }; - let toRaw = (t: t(_, _)): Raw.t(_, _) => { + let toJs = (t: t(_, _)): JS.t(_, _) => { client: t.client, context: t.context, displayName: t.displayName, errorPolicy: - t.errorPolicy - ->Belt.Option.map(Core.WatchQueryOptions.ErrorPolicy.toRaw), + t.errorPolicy->Belt.Option.map(Core.WatchQueryOptions.ErrorPolicy.toJs), onCompleted: t.onCompleted, onError: t.onError, fetchPolicy: t.fetchPolicy - ->Belt.Option.map(Core.WatchQueryOptions.WatchQueryFetchPolicy.toRaw), + ->Belt.Option.map(Core.WatchQueryOptions.WatchQueryFetchPolicy.toJs), notifyOnNetworkStatusChange: t.notifyOnNetworkStatusChange, query: t.query, pollInterval: t.pollInterval, @@ -71,70 +70,70 @@ module QueryHookOptions = { }; module QueryResult = { - module Raw = { - type t_fetchMoreOptions_updateQueryOptions('tData, 'raw_tVariables) = { - fetchMoreResult: Js.nullable('tData), - variables: Js.nullable('raw_tVariables), + module JS = { + type t_fetchMoreOptions_updateQueryOptions('parsedData, 'variables) = { + fetchMoreResult: Js.nullable('parsedData), + variables: Js.nullable('variables), }; - type t_fetchMoreOptions('raw_tData, 'raw_tVariables) = { + type t_fetchMoreOptions('jsData, 'variables) = { query: option(Graphql.Language.documentNode), - variables: option('raw_tVariables), + variables: option('variables), context: option(Js.Json.t), updateQuery: ( - 'raw_tData, - t_fetchMoreOptions_updateQueryOptions('raw_tData, 'raw_tVariables) + 'jsData, + t_fetchMoreOptions_updateQueryOptions('jsData, 'variables) ) => - 'raw_tData, + 'jsData, }; - type t('raw_tData, 'raw_tVariables) = { + type t('jsData, 'variables) = { fetchMore: - t_fetchMoreOptions('raw_tData, 'raw_tVariables) => - Js.Promise.t(Core.Types.ApolloQueryResult.Raw.t('raw_tData)), + t_fetchMoreOptions('jsData, 'variables) => + Js.Promise.t(Core.Types.ApolloQueryResult.JS.t('jsData)), called: bool, client: Apollo_Client__ApolloClient.t, - data: Js.nullable('raw_tData), + data: Js.nullable('jsData), error: Js.nullable(Errors.ApolloError.t), loading: bool, networkStatus: Core.NetworkStatus.t, }; }; - type t_updateQueryOptions('tData, 'raw_tVariables) = { - fetchMoreResult: option('tData), - variables: option('raw_tVariables), + type t_updateQueryOptions('parsedData, 'variables) = { + fetchMoreResult: option('parsedData), + variables: option('variables), }; - type t('tData, 'raw_tVariables) = { + type t('parsedData, 'variables) = { called: bool, client: Apollo_Client__ApolloClient.t, - data: option('tData), + data: option('parsedData), error: option(Errors.ApolloError.t), fetchMore: ( ~context: Js.Json.t=?, - ~variables: 'raw_tVariables=?, + ~variables: 'variables=?, ~updateQuery: ( - 'tData, - t_updateQueryOptions('tData, 'raw_tVariables) + 'parsedData, + t_updateQueryOptions('parsedData, 'variables) ) => - 'tData, + 'parsedData, unit ) => - Js.Promise.t(Core.Types.ApolloQueryResult.t('tData)), + Js.Promise.t(Core.Types.ApolloQueryResult.t('parsedData)), loading: bool, networkStatus: Core.NetworkStatus.t, }; - let fromRaw: + let fromJs: ( - Raw.t('raw_tData, 'raw_tVariables), - ~parse: 'raw_tData => 'tData, - ~serialize: 'tData => 'raw_tData + JS.t('jsData, 'variables), + ~parse: 'jsData => 'parsedData, + ~serialize: 'parsedData => 'jsData ) => - t('tData, 'raw_tVariables) = + t('parsedData, 'variables) = (raw, ~parse, ~serialize) => { called: raw.called, client: raw.client, @@ -160,7 +159,7 @@ module QueryResult = { ->Js.Promise.then_( jsResult => Js.Promise.resolve( - Core.Types.ApolloQueryResult.fromRaw(jsResult, ~parse), + Core.Types.ApolloQueryResult.fromJs(jsResult, ~parse), ), _, ); From 8f82251f75358373a08af8eef5f027ae489642ba Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Mon, 18 May 2020 07:43:43 -0500 Subject: [PATCH 04/21] refactor: switch to polymorphic variants and jsConverter --- .../core/Apollo_Client__Core_NetworkStatus.re | 29 +++++-------- .../Apollo_Client__Core_WatchQueryOptions.re | 42 ++++++++----------- 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re b/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re index ffd6be8..a37882d 100644 --- a/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re +++ b/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re @@ -1,20 +1,13 @@ +[@bs.deriving jsConverter] type t = - | Loading - | SetVariables - | FetchMore - | Refetch - | Poll - | Ready - | Error - | Unknown; + | [@bs.as 1] Loading + | [@bs.as 2] SetVariables + | [@bs.as 3] FetchMore + | [@bs.as 4] Refetch + | [@bs.as 5] Poll + | [@bs.as 6] Ready + | [@bs.as 7] Error; -let fromJs = - fun - | 1 => Loading - | 2 => SetVariables - | 3 => FetchMore - | 4 => Refetch - | 6 => Poll - | 7 => Ready - | 8 => Error - | _ => Unknown; +let toJs = tToJs; + +let fromJs = string => tFromJs(string)->Belt.Option.getExn; diff --git a/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re b/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re index dff7c30..7b0e89a 100644 --- a/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re +++ b/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re @@ -1,32 +1,24 @@ module ErrorPolicy = { - type t = - | None - | Ignore - | All; + [@bs.deriving jsConverter] + type t = [ | `none | `ignore | `all]; - let toJs = - fun - | None => "none" - | Ignore => "ignore" - | All => "all"; + let toJs = tToJs; + + let fromJs = string => tFromJs(string)->Belt.Option.getExn; }; module WatchQueryFetchPolicy = { - type t = - | CacheAndNetwork - // ...extends FetchPolicy - | CacheFirst - | NetworkOnly - | CacheOnly - | NoCache - | Standby; + [@bs.deriving jsConverter] + type t = [ + | [@bs.as "cache-and-network"] `cacheAndNetwork + | [@bs.as "cache-first"] `cacheFirst + | [@bs.as "cache-only"] `cacheOnly + | [@bs.as "network-only"] `networkOnly + | [@bs.as "no-cache"] `noCache + | `standby + ]; + + let toJs = tToJs; - let toJs = - fun - | CacheFirst => "cache-first" - | CacheAndNetwork => "cache-and-network" - | NetworkOnly => "network-only" - | CacheOnly => "cache-only" - | NoCache => "no-cache" - | Standby => "standby"; + let fromJs = string => tFromJs(string)->Belt.Option.getExn; }; From b0b09c8973031e66ce1f85271e1616a3163a1c5f Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Mon, 18 May 2020 08:08:21 -0500 Subject: [PATCH 05/21] refactor: use option instead of nullable where appropriate --- ...ollo_Client__Graphql_Error_GraphQLError.re | 4 +- .../core/Apollo_Client__Core_Types.re | 23 ++++------- .../react/types/Apollo_Client__React_Types.re | 41 +++++++++---------- 3 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re b/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re index 27f7b16..02dd23b 100644 --- a/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re +++ b/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re @@ -2,7 +2,7 @@ module Graphql_Location = Apollo_Client__Graphql_Location; type t = { message: string, - locations: Js.nullable(array(Graphql_Location.sourceLocation)), + locations: option(array(Graphql_Location.sourceLocation)), // Union? https://bucklescript.github.io/blog/2020/02/07/union-types-in-bucklescript - path: Js.nullable(array(string)) // ACTUAL: string | number + path: option(array(string)) // ACTUAL: string | number }; diff --git a/src/Apollo_Client/core/Apollo_Client__Core_Types.re b/src/Apollo_Client/core/Apollo_Client__Core_Types.re index 0803e76..07d7188 100644 --- a/src/Apollo_Client/core/Apollo_Client__Core_Types.re +++ b/src/Apollo_Client/core/Apollo_Client__Core_Types.re @@ -1,15 +1,6 @@ module Graphql = Apollo_Client__Graphql; module ApolloQueryResult = { - module JS = { - type t('jsData) = { - data: Js.nullable('jsData), - errors: Js.nullable(array(Graphql.Error.GraphQLError.t)), - loading: bool, - networkStatus: int, - }; - }; - type t('parsedData) = { data: option('parsedData), errors: option(array(Graphql.Error.GraphQLError.t)), @@ -17,11 +8,11 @@ module ApolloQueryResult = { networkStatus: int, }; - let fromJs = - ({data, errors, loading, networkStatus}: JS.t('jsData), ~parse) => { - data: data->Js.toOption->Belt.Option.map(parse), - errors: errors->Js.toOption, - loading, - networkStatus, - }; + let fromJs: (t('jsData), ~parse: 'jsData => 'parsedData) => t('parsedData) = + ({data, errors, loading, networkStatus}, ~parse) => { + data: data->Belt.Option.map(parse), + errors, + loading, + networkStatus, + }; }; diff --git a/src/Apollo_Client/react/types/Apollo_Client__React_Types.re b/src/Apollo_Client/react/types/Apollo_Client__React_Types.re index 0bab3c6..c262544 100644 --- a/src/Apollo_Client/react/types/Apollo_Client__React_Types.re +++ b/src/Apollo_Client/react/types/Apollo_Client__React_Types.re @@ -72,8 +72,8 @@ module QueryHookOptions = { module QueryResult = { module JS = { type t_fetchMoreOptions_updateQueryOptions('parsedData, 'variables) = { - fetchMoreResult: Js.nullable('parsedData), - variables: Js.nullable('variables), + fetchMoreResult: option('parsedData), + variables: option('variables), }; type t_fetchMoreOptions('jsData, 'variables) = { @@ -91,21 +91,16 @@ module QueryResult = { type t('jsData, 'variables) = { fetchMore: t_fetchMoreOptions('jsData, 'variables) => - Js.Promise.t(Core.Types.ApolloQueryResult.JS.t('jsData)), + Js.Promise.t(Core.Types.ApolloQueryResult.t('jsData)), called: bool, client: Apollo_Client__ApolloClient.t, - data: Js.nullable('jsData), - error: Js.nullable(Errors.ApolloError.t), + data: option('jsData), + error: option(Errors.ApolloError.t), loading: bool, networkStatus: Core.NetworkStatus.t, }; }; - type t_updateQueryOptions('parsedData, 'variables) = { - fetchMoreResult: option('parsedData), - variables: option('variables), - }; - type t('parsedData, 'variables) = { called: bool, client: Apollo_Client__ApolloClient.t, @@ -117,7 +112,10 @@ module QueryResult = { ~variables: 'variables=?, ~updateQuery: ( 'parsedData, - t_updateQueryOptions('parsedData, 'variables) + JS.t_fetchMoreOptions_updateQueryOptions( + 'parsedData, + 'variables, + ) ) => 'parsedData, unit @@ -134,23 +132,22 @@ module QueryResult = { ~serialize: 'parsedData => 'jsData ) => t('parsedData, 'variables) = - (raw, ~parse, ~serialize) => { - called: raw.called, - client: raw.client, - data: raw.data->Js.toOption->Belt.Option.map(parse), - error: raw.error->Js.toOption, + (js, ~parse, ~serialize) => { + called: js.called, + client: js.client, + data: js.data->Belt.Option.map(parse), + error: js.error, fetchMore: (~context=?, ~variables=?, ~updateQuery as jsUpdateQuery, ()) => { - raw.fetchMore({ + js.fetchMore({ context, query: None, updateQuery: (previousResult, {fetchMoreResult, variables}) => jsUpdateQuery( parse(previousResult), { - fetchMoreResult: - fetchMoreResult->Js.toOption->Belt.Option.map(parse), - variables: variables->Js.toOption, + fetchMoreResult: fetchMoreResult->Belt.Option.map(parse), + variables, }, ) ->serialize, @@ -164,7 +161,7 @@ module QueryResult = { _, ); }, - loading: raw.loading, - networkStatus: raw.networkStatus, + loading: js.loading, + networkStatus: js.networkStatus, }; }; From de4d6c3c511be22d2805b194a1db1181a5d7b5da Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sat, 23 May 2020 20:36:16 -0500 Subject: [PATCH 06/21] refactor: add some ApolloClient bindings and switch to FCM api --- .../Apollo_Client.re => ApolloClient.re} | 9 +- src/ApolloClient__ApolloClient.re | 269 ++++++++++++++ ...lient__Types.re => ApolloClient__Types.re} | 13 + ...lient__Utils.re => ApolloClient__Utils.re} | 0 src/ApolloHooks.re | 163 --------- src/ApolloHooksMutation.re | 208 ----------- src/ApolloHooksProvider.re | 5 - src/ApolloHooksQuery.re | 220 ----------- src/ApolloHooksSubscription.re | 70 ---- src/ApolloHooksTypes.re | 100 ----- .../graphql-tag/Apollo_Client__GraphqlTag.re | 3 - .../graphql/Apollo_Client__Graphql.re | 6 - .../error/Apollo_Client__Graphql_Error.re | 1 - src/Apollo_Client/core/Apollo_Client__Core.re | 3 - .../core/Apollo_Client__Core_Types.re | 18 - .../Apollo_Client__Core_WatchQueryOptions.re | 24 -- .../errors/Apollo_Client__Errors.re | 16 - .../react/Apollo_Client__React.re | 2 - .../hooks/Apollo_Client__React_UseQuery.re | 99 ----- .../react/types/Apollo_Client__React_Types.re | 167 --------- .../graphql-tag/ApolloClient__GraphqlTag.re | 3 + .../graphql/ApolloClient__Graphql.re | 7 + .../error/ApolloClient__Graphql_Error.re | 1 + ...olloClient__Graphql_Error_GraphQLError.re} | 2 +- .../ApolloClient__Graphql_Execution.re | 1 + ...ApolloClient__Graphql_Execution_Execute.re | 8 + .../ApolloClient__Graphql_Language.re} | 0 .../ApolloClient__Graphql_Location.re} | 0 .../core/ApolloClient__Cache_Core_Cache.re} | 0 .../core/ApolloClient__Cache_Core_Types.re | 101 +++++ src/core/ApolloClient__Core.re | 3 + .../ApolloClient__Core_NetworkStatus.re} | 0 src/core/ApolloClient__Core_Types.re | 124 +++++++ .../ApolloClient__Core_WatchQueryOptions.re | 236 ++++++++++++ src/errors/ApolloClient__Errors.re | 38 ++ .../core/ApolloClient__Link_Core_Types.re | 34 ++ src/react/ApolloClient__React.re | 2 + .../hooks/ApolloClient__React_UseQuery.re | 146 ++++++++ .../ApolloClient__React_UseSubscription.re | 122 +++++++ src/react/types/ApolloClient__React_Types.re | 345 ++++++++++++++++++ 40 files changed, 1460 insertions(+), 1109 deletions(-) rename src/{Apollo_Client/Apollo_Client.re => ApolloClient.re} (90%) create mode 100644 src/ApolloClient__ApolloClient.re rename src/{Apollo_Client/Apollo_Client__Types.re => ApolloClient__Types.re} (53%) rename src/{Apollo_Client/Apollo_Client__Utils.re => ApolloClient__Utils.re} (100%) delete mode 100644 src/ApolloHooks.re delete mode 100644 src/ApolloHooksMutation.re delete mode 100644 src/ApolloHooksProvider.re delete mode 100644 src/ApolloHooksQuery.re delete mode 100644 src/ApolloHooksSubscription.re delete mode 100644 src/ApolloHooksTypes.re delete mode 100644 src/Apollo_Client/_dependencies/graphql-tag/Apollo_Client__GraphqlTag.re delete mode 100644 src/Apollo_Client/_peerDependencies/graphql/Apollo_Client__Graphql.re delete mode 100644 src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error.re delete mode 100644 src/Apollo_Client/core/Apollo_Client__Core.re delete mode 100644 src/Apollo_Client/core/Apollo_Client__Core_Types.re delete mode 100644 src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re delete mode 100644 src/Apollo_Client/errors/Apollo_Client__Errors.re delete mode 100644 src/Apollo_Client/react/Apollo_Client__React.re delete mode 100644 src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re delete mode 100644 src/Apollo_Client/react/types/Apollo_Client__React_Types.re create mode 100644 src/_dependencies/graphql-tag/ApolloClient__GraphqlTag.re create mode 100644 src/_peerDependencies/graphql/ApolloClient__Graphql.re create mode 100644 src/_peerDependencies/graphql/error/ApolloClient__Graphql_Error.re rename src/{Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re => _peerDependencies/graphql/error/ApolloClient__Graphql_Error_GraphQLError.re} (80%) create mode 100644 src/_peerDependencies/graphql/execution/ApolloClient__Graphql_Execution.re create mode 100644 src/_peerDependencies/graphql/execution/ApolloClient__Graphql_Execution_Execute.re rename src/{Apollo_Client/_peerDependencies/graphql/language/Apollo_Client__Graphql_Language.re => _peerDependencies/graphql/language/ApolloClient__Graphql_Language.re} (100%) rename src/{Apollo_Client/_peerDependencies/graphql/location/Apollo_Client__Graphql_Location.re => _peerDependencies/graphql/location/ApolloClient__Graphql_Location.re} (100%) rename src/{Apollo_Client/Apollo_Client__ApolloClient.re => cache/core/ApolloClient__Cache_Core_Cache.re} (100%) create mode 100644 src/cache/core/ApolloClient__Cache_Core_Types.re create mode 100644 src/core/ApolloClient__Core.re rename src/{Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re => core/ApolloClient__Core_NetworkStatus.re} (100%) create mode 100644 src/core/ApolloClient__Core_Types.re create mode 100644 src/core/ApolloClient__Core_WatchQueryOptions.re create mode 100644 src/errors/ApolloClient__Errors.re create mode 100644 src/link/core/ApolloClient__Link_Core_Types.re create mode 100644 src/react/ApolloClient__React.re create mode 100644 src/react/hooks/ApolloClient__React_UseQuery.re create mode 100644 src/react/hooks/ApolloClient__React_UseSubscription.re create mode 100644 src/react/types/ApolloClient__React_Types.re diff --git a/src/Apollo_Client/Apollo_Client.re b/src/ApolloClient.re similarity index 90% rename from src/Apollo_Client/Apollo_Client.re rename to src/ApolloClient.re index 821426a..a1227a8 100644 --- a/src/Apollo_Client/Apollo_Client.re +++ b/src/ApolloClient.re @@ -35,10 +35,13 @@ // export { DocumentType, operationName, parser } from './react/parser/parser.js'; // export { useLazyQuery } from './react/hooks/useLazyQuery.js'; // export { useMutation } from './react/hooks/useMutation.js'; -// export { useSubscription } from './react/hooks/useSubscription.js'; // export { useApolloClient } from './react/hooks/useApolloClient.js'; // export { RenderPromises } from './react/ssr/RenderPromises.js'; -let useQuery = Apollo_Client__React_UseQuery.useQuery; +let useQuery = ApolloClient__React_UseQuery.useQuery; +let useSubscription = ApolloClient__React_UseSubscription.useSubscription; -let gql = Apollo_Client__GraphqlTag.gql; +module Extend = { + module Query = ApolloClient__React_UseQuery.Extend; + module Subscription = ApolloClient__React_UseSubscription.Extend; +}; diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re new file mode 100644 index 0000000..0c51d77 --- /dev/null +++ b/src/ApolloClient__ApolloClient.re @@ -0,0 +1,269 @@ +module ApolloQueryResult = ApolloClient__Core_Types.ApolloQueryResult; +module DataProxy = ApolloClient__Cache_Core_Types.DataProxy; +module ErrorPolicy = ApolloClient__Core_WatchQueryOptions.ErrorPolicy; +module FetchPolicy = ApolloClient__Core_WatchQueryOptions.FetchPolicy; +module FetchPolicy__noCacheExtracted = ApolloClient__Core_WatchQueryOptions.FetchPolicy__noCacheExtracted; +module GraphQL = ApolloClient__Graphql; +module GraphqlTag = ApolloClient__GraphqlTag; +module FetchResult = ApolloClient__Link_Core_Types.FetchResult; +module MutationOptions = ApolloClient__Core_WatchQueryOptions.MutationOptions; +module MutationQueryReducersMap = ApolloClient__Core_WatchQueryOptions.MutationQueryReducersMap; +module MutationUpdaterFn = ApolloClient__Core_WatchQueryOptions.MutationUpdaterFn; +module QueryOptions = ApolloClient__Core_WatchQueryOptions.QueryOptions; +module PureQueryOptions = ApolloClient__Core_Types.PureQueryOptions; +module RefetchQueryDescription = ApolloClient__Core_WatchQueryOptions.RefetchQueryDescription; +module Types = ApolloClient__Types; + +// /// + +// export interface DefaultOptions { +// watchQuery?: Partial; +// query?: Partial; +// mutate?: Partial; +// } + +// export declare type ApolloClientOptions = { +// uri?: string | UriFunction; +// credentials?: string; +// headers?: Record; +// link?: ApolloLink; +// cache: ApolloCache; +// ssrForceFetchDelay?: number; +// ssrMode?: boolean; +// connectToDevTools?: boolean; +// queryDeduplication?: boolean; +// defaultOptions?: DefaultOptions; +// assumeImmutableResults?: boolean; +// resolvers?: Resolvers | Resolvers[]; +// typeDefs?: string | string[] | DocumentNode | DocumentNode[]; +// fragmentMatcher?: FragmentMatcher; +// name?: string; +// version?: string; +// }; + +// export declare class ApolloClient implements DataProxy { +// link: ApolloLink; +// cache: ApolloCache; +// disableNetworkFetches: boolean; +// version: string; +// queryDeduplication: boolean; +// defaultOptions: DefaultOptions; +// readonly typeDefs: ApolloClientOptions['typeDefs']; +// private queryManager; +// private devToolsHookCb; +// private resetStoreCallbacks; +// private clearStoreCallbacks; +// private localState; +// constructor(options: ApolloClientOptions); +// stop(): void; +// watchQuery(options: WatchQueryOptions): ObservableQuery; +// subscribe(options: SubscriptionOptions): Observable>; +// readFragment(options: DataProxy.Fragment, optimistic?: boolean): T | null; +// writeFragment(options: DataProxy.WriteFragmentOptions): void; +// __actionHookForDevTools(cb: () => any): void; +// __requestRaw(payload: GraphQLRequest): Observable; +// resetStore(): Promise[] | null>; +// clearStore(): Promise; +// onResetStore(cb: () => Promise): () => void; +// onClearStore(cb: () => Promise): () => void; +// reFetchObservableQueries(includeStandby?: boolean): Promise[]>; +// extract(optimistic?: boolean): TCacheShape; +// restore(serializedState: TCacheShape): ApolloCache; +// addResolvers(resolvers: Resolvers | Resolvers[]): void; +// setResolvers(resolvers: Resolvers | Resolvers[]): void; +// getResolvers(): Resolvers; +// setLocalStateFragmentMatcher(fragmentMatcher: FragmentMatcher): void; +// } + +type t; + +type refetchQueryDescription = + | PureQueryOptions(PureQueryOptions.t('variables)): refetchQueryDescription + | String(string): refetchQueryDescription; + +module Js_ = { + // mutate(options: MutationOptions): Promise>; + [@bs.send] + external mutate: + (t, ~options: MutationOptions.Js_.t('jsData, 'variables)) => + Js.Promise.t(FetchResult.Js_.t('jsData)) = + "mutate"; + + // query(options: QueryOptions): Promise>; + [@bs.send] + external query: + (t, ~options: QueryOptions.Js_.t('variables)) => + Js.Promise.t(ApolloQueryResult.Js_.t('jsData)) = + "query"; + + // readQuery(options: DataProxy.Query, optimistic?: boolean): T | null; + [@bs.send] + external readQuery: + ( + t, + ~options: DataProxy.Query.Js_.t('variables), + ~optimistic: option(bool) + ) => + Js.nullable('jsData) = + "readQuery"; + + // writeQuery(options: DataProxy.WriteQueryOptions): void; + [@bs.send] + external writeQuery: + (t, ~options: DataProxy.WriteQueryOptions.Js_.t('jsData, 'variables)) => + unit = + "writeQuery"; +}; + +let mutate: + type data variables jsData jsVariables. + ( + t, + ~awaitRefetchQueries: bool=?, + ~context: Js.Json.t=?, + ~errorPolicy: ErrorPolicy.t=?, + ~fetchPolicy: FetchPolicy__noCacheExtracted.t=?, + ~optimisticResponse: variables => data=?, + ~refetchQueries: RefetchQueryDescription.t=?, + ~updateQueries: MutationQueryReducersMap.t(data)=?, + ~update: MutationUpdaterFn.t(data)=?, + ~variables: variables=?, + (module Types.Operation with + type t = data and + type Raw.t = jsData and + type Raw.t_variables = jsVariables) + ) => + Js.Promise.t(FetchResult.t(data)) = + ( + client, + ~awaitRefetchQueries=?, + ~context=?, + ~errorPolicy=?, + ~fetchPolicy=?, + ~optimisticResponse=?, + ~refetchQueries=?, + ~updateQueries=?, + ~update=?, + ~variables=?, + (module Definition), + ) => { + Js_.mutate( + client, + ~options= + MutationOptions.toJs( + { + awaitRefetchQueries, + context, + errorPolicy, + fetchPolicy, + mutation: GraphqlTag.gql(Definition.query), + optimisticResponse, + updateQueries, + refetchQueries, + update, + variables, + }, + ~parse=Definition.parse, + ~serialize=Definition.serialize, + ), + ) + ->Js.Promise.then_( + jsResult => + jsResult + ->FetchResult.fromJs(_, ~parse=Definition.parse) + ->Js.Promise.resolve, + _, + ); + }; + +let query: + type data variables jsData jsVariables. + ( + t, + ~context: Js.Json.t=?, + ~errorPolicy: ErrorPolicy.t=?, + ~fetchPolicy: FetchPolicy.t=?, + ~variables: variables=?, + (module Types.Operation with + type t = data and + type Raw.t = jsData and + type Raw.t_variables = jsVariables) + ) => + Js.Promise.t(ApolloQueryResult.t(data)) = + ( + client, + ~context=?, + ~errorPolicy=?, + ~fetchPolicy=?, + ~variables=?, + (module Definition), + ) => { + Js_.query( + client, + ~options= + QueryOptions.toJs({ + fetchPolicy, + query: GraphqlTag.gql(Definition.query), + variables, + errorPolicy, + context, + }), + ) + ->Js.Promise.then_( + jsResult => + jsResult + ->ApolloQueryResult.fromJs(_, ~parse=Definition.parse) + ->Js.Promise.resolve, + _, + ); + }; + +let readQuery: + type data variables jsData jsVariables. + ( + t, + ~id: string=?, + ~optimistic: bool=?, + ~variables: variables=?, + (module Types.Operation with + type t = data and + type Raw.t = jsData and + type Raw.t_variables = jsVariables) + ) => + option(data) = + (client, ~id=?, ~optimistic=?, ~variables=?, (module Definition)) => { + Js_.readQuery( + client, + ~options={id, query: GraphqlTag.gql(Definition.query), variables}, + ~optimistic, + ) + ->Js.toOption + ->Belt.Option.map(Definition.parse); + }; + +let writeQuery: + type data variables jsData jsVariables. + ( + t, + ~broadcast: bool=?, + ~data: data, + ~id: string=?, + ~variables: variables=?, + (module Types.Operation with + type t = data and + type Raw.t = jsData and + type Raw.t_variables = jsVariables) + ) => + unit = + (client, ~broadcast=?, ~data, ~id=?, ~variables=?, (module Definition)) => { + Js_.writeQuery( + client, + ~options={ + broadcast, + data, + id, + query: GraphqlTag.gql(Definition.query), + variables, + }, + ); + }; diff --git a/src/Apollo_Client/Apollo_Client__Types.re b/src/ApolloClient__Types.re similarity index 53% rename from src/Apollo_Client/Apollo_Client__Types.re rename to src/ApolloClient__Types.re index 041fe6f..2db60fe 100644 --- a/src/Apollo_Client/Apollo_Client__Types.re +++ b/src/ApolloClient__Types.re @@ -7,3 +7,16 @@ type graphqlDefinition('t, 'raw_t) = ( query, serialize('t, 'raw_t), ); + +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/Apollo_Client/Apollo_Client__Utils.re b/src/ApolloClient__Utils.re similarity index 100% rename from src/Apollo_Client/Apollo_Client__Utils.re rename to src/ApolloClient__Utils.re diff --git a/src/ApolloHooks.re b/src/ApolloHooks.re deleted file mode 100644 index 5d493c1..0000000 --- a/src/ApolloHooks.re +++ /dev/null @@ -1,163 +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; - -/** 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, - }; diff --git a/src/ApolloHooksMutation.re b/src/ApolloHooksMutation.re deleted file mode 100644 index 8c10eff..0000000 --- a/src/ApolloHooksMutation.re +++ /dev/null @@ -1,208 +0,0 @@ -open ApolloHooksTypes; - -type jsResult = { - . - "data": Js.Nullable.t(Js.Json.t), - "loading": bool, - "called": bool, - "error": Js.Nullable.t(apolloError), -}; - -type jsExecutionResult = { - . - "data": Js.Nullable.t(Js.Json.t), - "errors": Js.Nullable.t(array(graphqlError)), -}; - -type refetchQueries = jsExecutionResult => 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)), -}; - -type executionVariantResult('a) = - | Data('a) - | Errors(array(graphqlError)) - | NoData; - -/* The type of the 'full' result returned by the hook */ -type controlledResult('a) = { - loading: bool, - called: bool, - data: option('a), - error: option(apolloError), -}; - -/* The type of the 'simple' result returned by the hook */ -type controlledVariantResult('a) = - | Loading - | NotCalled - | Data('a) - | Error(apolloError) - | NoData; - -[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; - -type mutationResult('a) = {. "data": option('a)}; - -[@bs.deriving abstract] -type options('a) = { - [@bs.optional] - variables: Js.Json.t, - [@bs.optional] - mutation: option(ReasonApolloTypes.queryString), - [@bs.optional] - client: ApolloClient.generatedApolloClient, - [@bs.optional] - refetchQueries, - [@bs.optional] - awaitRefetchQueries: bool, - [@bs.optional] - update: (ApolloClient.generatedApolloClient, mutationResult('a)) => unit, - [@bs.optional] - optimisticResponse: Js.Json.t, - [@bs.optional] - context: Context.t, -}; - -type jsMutate('a) = (. options('a)) => Js.Promise.t(jsExecutionResult); - -type mutation('a) = - ( - ~variables: Js.Json.t=?, - ~client: ApolloClient.generatedApolloClient=?, - ~refetchQueries: refetchQueries=?, - ~awaitRefetchQueries: bool=?, - ~optimisticResponse: Js.Json.t=?, - unit - ) => - Js.Promise.t((executionVariantResult('a), executionResult('a))); - -[@bs.module "@apollo/react-hooks"] -external useMutationJs: - (. ReasonApolloTypes.queryString, options('a)) => (jsMutate('a), jsResult) = - "useMutation"; - -exception Error(string); - -let useMutation: - ( - ~client: ApolloClient.generatedApolloClient=?, - ~variables: Js.Json.t=?, - ~refetchQueries: refetchQueries=?, - ~awaitRefetchQueries: bool=?, - ~update: (ApolloClient.generatedApolloClient, mutationResult('data)) => - unit - =?, - ~optimisticResponse: Js.Json.t=?, - ~context: Context.t=?, - ApolloHooksTypes.graphqlDefinition('data, _, _) - ) => - ( - mutation('data), - controlledVariantResult('data), - controlledResult('data), - ) = - ( - ~client=?, - ~variables=?, - ~refetchQueries=?, - ~awaitRefetchQueries=?, - ~update=?, - ~optimisticResponse=?, - ~context=?, - (parse, query, _), - ) => { - let (jsMutate, jsResult) = - useMutationJs(. - gql(. query), - options( - ~client?, - ~variables?, - ~refetchQueries?, - ~awaitRefetchQueries?, - ~update?, - ~optimisticResponse?, - ~context?, - (), - ), - ); - - let mutate = - React.useMemo1( - ( - (), - ~variables=?, - ~client=?, - ~refetchQueries=?, - ~awaitRefetchQueries=?, - ~optimisticResponse=?, - (), - ) => - jsMutate(. - options( - ~variables?, - ~client?, - ~refetchQueries?, - ~awaitRefetchQueries?, - ~optimisticResponse?, - (), - ), - ) - |> 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 simple = - switch (full) { - | {errors: Some(errors)} => ( - Errors(errors): executionVariantResult('data) - ) - | {data: Some(data)} => Data(data) - | {errors: None, data: None} => NoData - }; - - (simple, full) |> Js.Promise.resolve; - }), - [|variables|], - ); - - let full = - React.useMemo1( - () => - { - loading: jsResult##loading, - called: jsResult##called, - data: - jsResult##data->Js.Nullable.toOption->Belt.Option.map(parse), - error: jsResult##error->Js.Nullable.toOption, - }, - [|jsResult|], - ); - - let simple = - React.useMemo1( - () => - switch (full) { - | {loading: true} => Loading - | {error: Some(error)} => Error(error) - | {data: Some(data)} => Data(data) - | {called: false} => NotCalled - | _ => NoData - }, - [|full|], - ); - - (mutate, simple, full); - }; diff --git a/src/ApolloHooksProvider.re b/src/ApolloHooksProvider.re deleted file mode 100644 index 7ad79c1..0000000 --- a/src/ApolloHooksProvider.re +++ /dev/null @@ -1,5 +0,0 @@ -[@bs.module "@apollo/react-hooks"] [@react.component] -external make: - (~client: ApolloClient.generatedApolloClient, ~children: React.element) => - React.element = - "ApolloProvider"; \ No newline at end of file diff --git a/src/ApolloHooksQuery.re b/src/ApolloHooksQuery.re deleted file mode 100644 index 0357526..0000000 --- a/src/ApolloHooksQuery.re +++ /dev/null @@ -1,220 +0,0 @@ -open ApolloHooksTypes; - -type variant('a) = - | Data('a) - | Error(apolloError) - | Loading - | NoData; - -/** - * - * apollo-client/src/core/ObservableQuery.ts - */ -[@bs.deriving abstract] -type updateQueryOptions = { - [@bs.optional] - fetchMoreResult: Js.Json.t, - [@bs.optional] - variables: Js.Json.t, -}; - -type updateQueryT = (Js.Json.t, updateQueryOptions) => Js.Json.t; - -/** - * https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/watchQueryOptions.ts#L139 - */ -type updateSubscriptionOptionsJs = { - . - "subscriptionData": {. "data": Js.Json.t}, - "variables": Js.Nullable.t(Js.Json.t), -}; - -type updateQuerySubscribeToMoreT = - (Js.Json.t, updateSubscriptionOptionsJs) => Js.Json.t; - -[@bs.deriving abstract] -type subscribeToMoreOptionsJs = { - document: ReasonApolloTypes.queryString, - [@bs.optional] - variables: Js.Json.t, - [@bs.optional] - updateQuery: updateQuerySubscribeToMoreT, -}; - -type unsubscribeFnT = unit => unit; - -type refetch('a) = (~variables: Js.Json.t=?, unit) => Js.Promise.t('a); -type queryResult('a) = { - data: option('a), - loading: bool, - error: option(apolloError), - refetch: refetch('a), - fetchMore: - (~variables: Js.Json.t=?, ~updateQuery: updateQueryT, unit) => - Js.Promise.t(unit), - networkStatus: ApolloHooksTypes.networkStatus, - startPolling: int => unit, - stopPolling: unit => unit, - subscribeToMore: - ( - ~document: ReasonApolloTypes.queryString, - ~variables: Js.Json.t=?, - ~updateQuery: updateQuerySubscribeToMoreT=?, - unit - ) => - unsubscribeFnT, -}; - -/** - * apollo-client/src/core/watchQueryOptions.ts - */ -[@bs.deriving abstract] -type fetchMoreOptions = { - [@bs.optional] - variables: Js.Json.t, - updateQuery: updateQueryT, -}; - -[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; - -[@bs.deriving abstract] -type options = { - [@bs.optional] - variables: Js.Json.t, - [@bs.optional] - client: ApolloClient.generatedApolloClient, - [@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, -}; - -[@bs.module "@apollo/react-hooks"] -external useQueryJs: - (ReasonApolloTypes.queryString, options) => - { - . - "data": Js.Nullable.t(Js.Json.t), - "loading": bool, - "error": Js.Nullable.t(apolloError), - [@bs.meth] - "refetch": Js.Nullable.t(Js.Json.t) => Js.Promise.t(Js.Json.t), - [@bs.meth] "fetchMore": fetchMoreOptions => Js.Promise.t(unit), - "networkStatus": Js.Nullable.t(int), - [@bs.meth] "stopPolling": unit => unit, - [@bs.meth] "startPolling": int => unit, - [@bs.meth] "subscribeToMore": subscribeToMoreOptionsJs => unsubscribeFnT, - } = - "useQuery"; - -let useQuery: - ( - ~client: ApolloClient.generatedApolloClient=?, - ~variables: Js.Json.t=?, - ~notifyOnNetworkStatusChange: bool=?, - ~fetchPolicy: ApolloHooksTypes.fetchPolicy=?, - ~errorPolicy: ApolloHooksTypes.errorPolicy=?, - ~skip: bool=?, - ~pollInterval: int=?, - ~context: Context.t=?, - graphqlDefinition('data, _, _) - ) => - (variant('data), queryResult('data)) = - ( - ~client=?, - ~variables=?, - ~notifyOnNetworkStatusChange=?, - ~fetchPolicy=?, - ~errorPolicy=?, - ~skip=?, - ~pollInterval=?, - ~context=?, - (parse, query, _), - ) => { - 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 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, ()), - ), - 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/ApolloHooksSubscription.re b/src/ApolloHooksSubscription.re deleted file mode 100644 index 81aea7a..0000000 --- a/src/ApolloHooksSubscription.re +++ /dev/null @@ -1,70 +0,0 @@ -type error = {. "message": string}; - -type variant('a) = - | Data('a) - | Error(error) - | Loading - | NoData; - -type result('a) = { - data: option('a), - loading: bool, - error: option(error), -}; - -[@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; - -[@bs.deriving abstract] -type options = { - [@bs.optional] - variables: Js.Json.t, - [@bs.optional] - skip: bool, - [@bs.optional] - onSubscriptionData: unit => unit, - [@bs.optional] - client: ApolloClient.generatedApolloClient, -}; - -[@bs.module "@apollo/react-hooks"] -external useSubscriptionJs: - (ReasonApolloTypes.queryString, options) => - { - . - "data": Js.Nullable.t(Js.Json.t), - "loading": bool, - "error": Js.Nullable.t(error), - } = - "useSubscription"; - -let useSubscription: - ( - ~variables: Js.Json.t=?, - ~client: ApolloClient.generatedApolloClient=?, - ~skip: bool=?, - ApolloHooksTypes.graphqlDefinition('data, _, _) - ) => - (variant('data), result('data)) = - (~variables=?, ~client=?, ~skip=?, (parse, query, _)) => { - let jsResult = - useSubscriptionJs( - gql(. 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, - }; - - ( - switch (result) { - | {data: Some(data)} => Data(data) - | {error: Some(error)} => Error(error) - | {loading: true} => Loading - | _ => NoData - }, - result, - ); - }; diff --git a/src/ApolloHooksTypes.re b/src/ApolloHooksTypes.re deleted file mode 100644 index cd27d31..0000000 --- a/src/ApolloHooksTypes.re +++ /dev/null @@ -1,100 +0,0 @@ -/** - * apollo-client/src/core/networkStatus - */ -type networkStatus = - | Loading - | SetVariables - | FetchMore - | Refetch - | Poll - | Ready - | Error - | Unknown; - -let toNetworkStatus = (status: Js.Nullable.t(int)) => { - switch (status->Js.Nullable.toOption) { - | Some(1) => Loading - | Some(2) => SetVariables - | Some(3) => FetchMore - | Some(4) => Refetch - | Some(6) => Poll - | Some(7) => Ready - | Some(8) => Error - | _ => Unknown - }; -}; - -/** - * apollo-client/src/core/watchQueryOptions.ts - */ -type fetchPolicy = - | CacheFirst - | CacheAndNetwork - | NetworkOnly - | CacheOnly - | NoCache - | Standby; - -let fetchPolicyToJs = fetchPolicy => { - switch (fetchPolicy) { - | CacheFirst => "cache-first" - | CacheAndNetwork => "cache-and-network" - | NetworkOnly => "network-only" - | CacheOnly => "cache-only" - | NoCache => "no-cache" - | Standby => "standby" - }; -}; - -/** - * apollo-client/src/core/watchQueryOptions.ts - */ -type errorPolicy = - | None - | Ignore - | All; - -let errorPolicyToJs = errorPolicy => - switch (errorPolicy) { - | None => "none" - | Ignore => "ignore" - | 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('a) = Js.Json.t => 'a; -type query = string; -type composeVariables('returnType, 'hookReturnType) = - (Js.Json.t => 'returnType) => 'hookReturnType; - -type graphqlDefinition('data, 'returnType, 'hookReturnType) = ( - parse('data), - query, - composeVariables('returnType, 'hookReturnType), -); - -module Context = { - type t = Js.Dict.t(string); - let make = (context): t => Js.Dict.fromList(context); -}; diff --git a/src/Apollo_Client/_dependencies/graphql-tag/Apollo_Client__GraphqlTag.re b/src/Apollo_Client/_dependencies/graphql-tag/Apollo_Client__GraphqlTag.re deleted file mode 100644 index 1d59482..0000000 --- a/src/Apollo_Client/_dependencies/graphql-tag/Apollo_Client__GraphqlTag.re +++ /dev/null @@ -1,3 +0,0 @@ -[@bs.module "graphql-tag"] -external gql: string => Apollo_Client__Graphql_Language.documentNode = - "default"; diff --git a/src/Apollo_Client/_peerDependencies/graphql/Apollo_Client__Graphql.re b/src/Apollo_Client/_peerDependencies/graphql/Apollo_Client__Graphql.re deleted file mode 100644 index fb9b8d9..0000000 --- a/src/Apollo_Client/_peerDependencies/graphql/Apollo_Client__Graphql.re +++ /dev/null @@ -1,6 +0,0 @@ -module Error = Apollo_Client__Graphql_Error; -module GraphQLError = Apollo_Client__Graphql_Error_GraphQLError; -module Language = Apollo_Client__Graphql_Language; -module Location = Apollo_Client__Graphql_Location; - -type documentNode; diff --git a/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error.re b/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error.re deleted file mode 100644 index a88f2a6..0000000 --- a/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error.re +++ /dev/null @@ -1 +0,0 @@ -module GraphQLError = Apollo_Client__Graphql_Error_GraphQLError; diff --git a/src/Apollo_Client/core/Apollo_Client__Core.re b/src/Apollo_Client/core/Apollo_Client__Core.re deleted file mode 100644 index c5020ae..0000000 --- a/src/Apollo_Client/core/Apollo_Client__Core.re +++ /dev/null @@ -1,3 +0,0 @@ -module NetworkStatus = Apollo_Client__Core_NetworkStatus; -module Types = Apollo_Client__Core_Types; -module WatchQueryOptions = Apollo_Client__Core_WatchQueryOptions; diff --git a/src/Apollo_Client/core/Apollo_Client__Core_Types.re b/src/Apollo_Client/core/Apollo_Client__Core_Types.re deleted file mode 100644 index 07d7188..0000000 --- a/src/Apollo_Client/core/Apollo_Client__Core_Types.re +++ /dev/null @@ -1,18 +0,0 @@ -module Graphql = Apollo_Client__Graphql; - -module ApolloQueryResult = { - type t('parsedData) = { - data: option('parsedData), - errors: option(array(Graphql.Error.GraphQLError.t)), - loading: bool, - networkStatus: int, - }; - - let fromJs: (t('jsData), ~parse: 'jsData => 'parsedData) => t('parsedData) = - ({data, errors, loading, networkStatus}, ~parse) => { - data: data->Belt.Option.map(parse), - errors, - loading, - networkStatus, - }; -}; diff --git a/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re b/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re deleted file mode 100644 index 7b0e89a..0000000 --- a/src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re +++ /dev/null @@ -1,24 +0,0 @@ -module ErrorPolicy = { - [@bs.deriving jsConverter] - type t = [ | `none | `ignore | `all]; - - let toJs = tToJs; - - let fromJs = string => tFromJs(string)->Belt.Option.getExn; -}; - -module WatchQueryFetchPolicy = { - [@bs.deriving jsConverter] - type t = [ - | [@bs.as "cache-and-network"] `cacheAndNetwork - | [@bs.as "cache-first"] `cacheFirst - | [@bs.as "cache-only"] `cacheOnly - | [@bs.as "network-only"] `networkOnly - | [@bs.as "no-cache"] `noCache - | `standby - ]; - - let toJs = tToJs; - - let fromJs = string => tFromJs(string)->Belt.Option.getExn; -}; diff --git a/src/Apollo_Client/errors/Apollo_Client__Errors.re b/src/Apollo_Client/errors/Apollo_Client__Errors.re deleted file mode 100644 index 00f6da5..0000000 --- a/src/Apollo_Client/errors/Apollo_Client__Errors.re +++ /dev/null @@ -1,16 +0,0 @@ -module Graphql = Apollo_Client__Graphql; - -module ApolloError = { - type t = { - extraInfo: Js.Json.t, - graphQLErrors: array(Graphql.Error.GraphQLError.t), - networkError: Js.nullable(Js.Exn.t), - // ...extends Error - name: string, - message: string, - stack: option(string), - }; - // type errorOptions ={ graphQLErrors, networkError, errorMessage, extraInfo}; - // [@bs.new] [@bs.module "@apollo/client"] - // external make: errorOptions => t = "ApolloError"; -}; diff --git a/src/Apollo_Client/react/Apollo_Client__React.re b/src/Apollo_Client/react/Apollo_Client__React.re deleted file mode 100644 index 5c3061e..0000000 --- a/src/Apollo_Client/react/Apollo_Client__React.re +++ /dev/null @@ -1,2 +0,0 @@ -module Types = Apollo_Client__React_Types; -let useQuery = Apollo_Client__React_UseQuery.useQuery; diff --git a/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re b/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re deleted file mode 100644 index 12e2162..0000000 --- a/src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re +++ /dev/null @@ -1,99 +0,0 @@ -module Core = Apollo_Client__Core; -module Errors = Apollo_Client__Errors; -module Graphql = Apollo_Client__Graphql; -module GraphqlTag = Apollo_Client__GraphqlTag; -module React_Types = Apollo_Client__React_Types; - -type simpleQueryResult('a) = - | Data('a) - | Error(Errors.ApolloError.t) - | Loading - | NoData; - -module JS = { - [@bs.module "@apollo/client"] - external useQuery: - ( - ~query: Graphql.Language.documentNode, - ~options: React_Types.QueryHookOptions.t('jsData, 'variables)=? - ) => - React_Types.QueryResult.JS.t('jsData, 'variables) = - "useQuery"; -}; - -let useQuery: - ( - ~client: Apollo_Client__ApolloClient.t=?, - ~context: Js.Json.t=?, - ~displayName: string=?, - ~errorPolicy: Core.WatchQueryOptions.ErrorPolicy.t=?, - ~fetchPolicy: Core.WatchQueryOptions.WatchQueryFetchPolicy.t=?, - ~notifyOnNetworkStatusChange: bool=?, - ~onCompleted: 'jsData => unit=?, - ~onError: Errors.ApolloError.t => unit=?, - ~partialRefetch: bool=?, - ~pollInterval: int=?, - ~skip: bool=?, - ~ssr: bool=?, - ~variables: 'variables=?, - Apollo_Client__Types.graphqlDefinition('parsedData, 'jsData) - ) => - ( - simpleQueryResult('parsedData), - React_Types.QueryResult.t('parsedData, 'variables), - ) = - ( - ~client=?, - ~context=?, - ~displayName=?, - ~errorPolicy=?, - ~fetchPolicy=?, - ~notifyOnNetworkStatusChange=?, - ~onCompleted=?, - ~onError=?, - ~partialRefetch=?, - ~pollInterval=?, - ~skip=?, - ~ssr=?, - ~variables=?, - (parse, query, serialize), - ) => { - let jsQueryResult = - JS.useQuery( - ~query=GraphqlTag.gql(query), - ~options={ - client, - context, - displayName, - errorPolicy, - fetchPolicy, - onCompleted, - onError, - notifyOnNetworkStatusChange, - partialRefetch, - pollInterval, - query: None, - skip, - ssr, - variables, - }, - ); - - Apollo_Client__Utils.useGuaranteedMemo1( - () => { - let queryResult = - jsQueryResult->React_Types.QueryResult.fromJs(~parse, ~serialize); - - let simple = - switch (queryResult) { - | {loading: true} => Loading - | {error: Some(error)} => Error(error) - | {data: Some(data)} => Data(data) - | _ => NoData - }; - - (simple, queryResult); - }, - jsQueryResult, - ); - }; diff --git a/src/Apollo_Client/react/types/Apollo_Client__React_Types.re b/src/Apollo_Client/react/types/Apollo_Client__React_Types.re deleted file mode 100644 index c262544..0000000 --- a/src/Apollo_Client/react/types/Apollo_Client__React_Types.re +++ /dev/null @@ -1,167 +0,0 @@ -module Core = Apollo_Client__Core; -module Errors = Apollo_Client__Errors; -module Graphql = Apollo_Client__Graphql; - -module QueryHookOptions = { - module JS = { - type t('jsData, 'variables) = { - query: option(Graphql.documentNode), - // ...extends QueryFunctionOptions - displayName: option(string), - skip: option(bool), - onCompleted: option('jsData => unit), - onError: option(Errors.ApolloError.t => unit), - // ..extends BaseQueryOptions - client: option(Apollo_Client__ApolloClient.t), - context: option(Js.Json.t), // ACTUAL: Record - errorPolicy: option(string), - fetchPolicy: option(string), - notifyOnNetworkStatusChange: option(bool), - pollInterval: option(int), - ssr: option(bool), - variables: option('variables), - partialRefetch: option(bool), - // INTENTIONALLY IGNORED - // returnPartialData: option(bool), - }; - }; - - type t('jsData, 'variables) = { - query: option(Graphql.documentNode), - // ...extends QueryFunctionOptions - displayName: option(string), - skip: option(bool), - // consider parsing? - onCompleted: option('jsData => unit), - onError: option(Errors.ApolloError.t => unit), - // ...extends BaseQueryOptions - client: option(Apollo_Client__ApolloClient.t), - context: option(Js.Json.t), - errorPolicy: option(Core.WatchQueryOptions.ErrorPolicy.t), - fetchPolicy: option(Core.WatchQueryOptions.WatchQueryFetchPolicy.t), - notifyOnNetworkStatusChange: option(bool), - partialRefetch: option(bool), - pollInterval: option(int), - // INTENTIONALLY IGNORED - // returnPartialData: option(bool), - ssr: option(bool), - variables: option('variables), - }; - - let toJs = (t: t(_, _)): JS.t(_, _) => { - client: t.client, - context: t.context, - displayName: t.displayName, - errorPolicy: - t.errorPolicy->Belt.Option.map(Core.WatchQueryOptions.ErrorPolicy.toJs), - onCompleted: t.onCompleted, - onError: t.onError, - fetchPolicy: - t.fetchPolicy - ->Belt.Option.map(Core.WatchQueryOptions.WatchQueryFetchPolicy.toJs), - notifyOnNetworkStatusChange: t.notifyOnNetworkStatusChange, - query: t.query, - pollInterval: t.pollInterval, - partialRefetch: t.partialRefetch, - skip: t.skip, - ssr: t.ssr, - variables: t.variables, - }; -}; - -module QueryResult = { - module JS = { - type t_fetchMoreOptions_updateQueryOptions('parsedData, 'variables) = { - fetchMoreResult: option('parsedData), - variables: option('variables), - }; - - type t_fetchMoreOptions('jsData, 'variables) = { - query: option(Graphql.Language.documentNode), - variables: option('variables), - context: option(Js.Json.t), - updateQuery: - ( - 'jsData, - t_fetchMoreOptions_updateQueryOptions('jsData, 'variables) - ) => - 'jsData, - }; - - type t('jsData, 'variables) = { - fetchMore: - t_fetchMoreOptions('jsData, 'variables) => - Js.Promise.t(Core.Types.ApolloQueryResult.t('jsData)), - called: bool, - client: Apollo_Client__ApolloClient.t, - data: option('jsData), - error: option(Errors.ApolloError.t), - loading: bool, - networkStatus: Core.NetworkStatus.t, - }; - }; - - type t('parsedData, 'variables) = { - called: bool, - client: Apollo_Client__ApolloClient.t, - data: option('parsedData), - error: option(Errors.ApolloError.t), - fetchMore: - ( - ~context: Js.Json.t=?, - ~variables: 'variables=?, - ~updateQuery: ( - 'parsedData, - JS.t_fetchMoreOptions_updateQueryOptions( - 'parsedData, - 'variables, - ) - ) => - 'parsedData, - unit - ) => - Js.Promise.t(Core.Types.ApolloQueryResult.t('parsedData)), - loading: bool, - networkStatus: Core.NetworkStatus.t, - }; - - let fromJs: - ( - JS.t('jsData, 'variables), - ~parse: 'jsData => 'parsedData, - ~serialize: 'parsedData => 'jsData - ) => - t('parsedData, 'variables) = - (js, ~parse, ~serialize) => { - called: js.called, - client: js.client, - data: js.data->Belt.Option.map(parse), - error: js.error, - fetchMore: - (~context=?, ~variables=?, ~updateQuery as jsUpdateQuery, ()) => { - js.fetchMore({ - context, - query: None, - updateQuery: (previousResult, {fetchMoreResult, variables}) => - jsUpdateQuery( - parse(previousResult), - { - fetchMoreResult: fetchMoreResult->Belt.Option.map(parse), - variables, - }, - ) - ->serialize, - variables, - }) - ->Js.Promise.then_( - jsResult => - Js.Promise.resolve( - Core.Types.ApolloQueryResult.fromJs(jsResult, ~parse), - ), - _, - ); - }, - loading: js.loading, - networkStatus: js.networkStatus, - }; -}; diff --git a/src/_dependencies/graphql-tag/ApolloClient__GraphqlTag.re b/src/_dependencies/graphql-tag/ApolloClient__GraphqlTag.re new file mode 100644 index 0000000..5dac315 --- /dev/null +++ b/src/_dependencies/graphql-tag/ApolloClient__GraphqlTag.re @@ -0,0 +1,3 @@ +[@bs.module "graphql-tag"] +external gql: string => ApolloClient__Graphql_Language.documentNode = + "default"; diff --git a/src/_peerDependencies/graphql/ApolloClient__Graphql.re b/src/_peerDependencies/graphql/ApolloClient__Graphql.re new file mode 100644 index 0000000..01040a9 --- /dev/null +++ b/src/_peerDependencies/graphql/ApolloClient__Graphql.re @@ -0,0 +1,7 @@ +module Error = ApolloClient__Graphql_Error; +module Execution = ApolloClient__Graphql_Execution; +module GraphQLError = ApolloClient__Graphql_Error_GraphQLError; +module Language = ApolloClient__Graphql_Language; +module Location = ApolloClient__Graphql_Location; + +type documentNode = Language.documentNode; diff --git a/src/_peerDependencies/graphql/error/ApolloClient__Graphql_Error.re b/src/_peerDependencies/graphql/error/ApolloClient__Graphql_Error.re new file mode 100644 index 0000000..ff94561 --- /dev/null +++ b/src/_peerDependencies/graphql/error/ApolloClient__Graphql_Error.re @@ -0,0 +1 @@ +module GraphQLError = ApolloClient__Graphql_Error_GraphQLError; diff --git a/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re b/src/_peerDependencies/graphql/error/ApolloClient__Graphql_Error_GraphQLError.re similarity index 80% rename from src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re rename to src/_peerDependencies/graphql/error/ApolloClient__Graphql_Error_GraphQLError.re index 02dd23b..56ebf5a 100644 --- a/src/Apollo_Client/_peerDependencies/graphql/error/Apollo_Client__Graphql_Error_GraphQLError.re +++ b/src/_peerDependencies/graphql/error/ApolloClient__Graphql_Error_GraphQLError.re @@ -1,4 +1,4 @@ -module Graphql_Location = Apollo_Client__Graphql_Location; +module Graphql_Location = ApolloClient__Graphql_Location; type t = { message: string, diff --git a/src/_peerDependencies/graphql/execution/ApolloClient__Graphql_Execution.re b/src/_peerDependencies/graphql/execution/ApolloClient__Graphql_Execution.re new file mode 100644 index 0000000..c2dd08e --- /dev/null +++ b/src/_peerDependencies/graphql/execution/ApolloClient__Graphql_Execution.re @@ -0,0 +1 @@ +module Execute = ApolloClient__Graphql_Execution_Execute; diff --git a/src/_peerDependencies/graphql/execution/ApolloClient__Graphql_Execution_Execute.re b/src/_peerDependencies/graphql/execution/ApolloClient__Graphql_Execution_Execute.re new file mode 100644 index 0000000..5bbcb0f --- /dev/null +++ b/src/_peerDependencies/graphql/execution/ApolloClient__Graphql_Execution_Execute.re @@ -0,0 +1,8 @@ +module GraphQLError = ApolloClient__Graphql_Error_GraphQLError; + +module ExecutionResult = { + type t('tData) = { + errors: option(GraphQLError.t), + data: option('tData), + }; +}; diff --git a/src/Apollo_Client/_peerDependencies/graphql/language/Apollo_Client__Graphql_Language.re b/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language.re similarity index 100% rename from src/Apollo_Client/_peerDependencies/graphql/language/Apollo_Client__Graphql_Language.re rename to src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language.re diff --git a/src/Apollo_Client/_peerDependencies/graphql/location/Apollo_Client__Graphql_Location.re b/src/_peerDependencies/graphql/location/ApolloClient__Graphql_Location.re similarity index 100% rename from src/Apollo_Client/_peerDependencies/graphql/location/Apollo_Client__Graphql_Location.re rename to src/_peerDependencies/graphql/location/ApolloClient__Graphql_Location.re diff --git a/src/Apollo_Client/Apollo_Client__ApolloClient.re b/src/cache/core/ApolloClient__Cache_Core_Cache.re similarity index 100% rename from src/Apollo_Client/Apollo_Client__ApolloClient.re rename to src/cache/core/ApolloClient__Cache_Core_Cache.re diff --git a/src/cache/core/ApolloClient__Cache_Core_Types.re b/src/cache/core/ApolloClient__Cache_Core_Types.re new file mode 100644 index 0000000..f59dda3 --- /dev/null +++ b/src/cache/core/ApolloClient__Cache_Core_Types.re @@ -0,0 +1,101 @@ +module Graphql = ApolloClient__Graphql; +module DataProxy = { + module Query = { + module Js_ = { + // interface Query { + // query: DocumentNode; + // variables?: TVariables; + // id?: string; + // } + type t('variables) = { + query: Graphql.documentNode, + variables: option('variables), + id: option(string), + }; + }; + + type t('variables) = Js_.t('variables); + }; + + module Fragment = { + module Js_ = { + // interface Fragment { + // id: string; + // fragment: DocumentNode; + // fragmentName?: string; + // variables?: TVariables; + // } + type t('variables) = { + id: string, + fragment: Graphql.documentNode, + fragmentName: option(string), + variables: option('variables), + }; + }; + + type t('variables) = Js_.t('variables); + }; + + module WriteQueryOptions = { + module Js_ = { + // interface WriteQueryOptions extends Query { + // data: TData; + // broadcast?: boolean; + // } + type t('jsData, 'variables) = { + data: 'jsData, + broadcast: option(bool), + // ...extends Query + query: Graphql.documentNode, + variables: option('variables), + id: option(string), + }; + }; + + type t('data, 'variables) = { + data: 'data, + broadcast: option(bool), + query: Graphql.documentNode, + variables: option('variables), + id: option(string), + }; + + let toJs: + (t('data, 'variables), ~parse: 'jsData => 'data) => + Js_.t('jsData, 'variables) = + (t, ~parse) => { + data: t.data->parse, + broadcast: t.broadcast, + query: t.query, + variables: t.variables, + id: t.id, + }; + }; + + module WriteFragmentOptions = { + module Js_ = { + // interface WriteFragmentOptions extends Fragment { + // data: TData; + // broadcast?: boolean; + // } + type t('jsData, 'variables) = { + data: 'jsData, + broadcast: option(bool), + // ...extends Fragment + id: string, + fragment: Graphql.documentNode, + fragmentName: option(string), + variables: option('variables), + }; + }; + + type t('data, 'variables) = { + data: 'data, + broadcast: option(bool), + id: string, + fragment: Graphql.documentNode, + fragmentName: option(string), + variables: option('variables), + }; + }; +}; diff --git a/src/core/ApolloClient__Core.re b/src/core/ApolloClient__Core.re new file mode 100644 index 0000000..96ec4ff --- /dev/null +++ b/src/core/ApolloClient__Core.re @@ -0,0 +1,3 @@ +module NetworkStatus = ApolloClient__Core_NetworkStatus; +module Types = ApolloClient__Core_Types; +module WatchQueryOptions = ApolloClient__Core_WatchQueryOptions; diff --git a/src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re b/src/core/ApolloClient__Core_NetworkStatus.re similarity index 100% rename from src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re rename to src/core/ApolloClient__Core_NetworkStatus.re diff --git a/src/core/ApolloClient__Core_Types.re b/src/core/ApolloClient__Core_Types.re new file mode 100644 index 0000000..5e6b749 --- /dev/null +++ b/src/core/ApolloClient__Core_Types.re @@ -0,0 +1,124 @@ +module Graphql = ApolloClient__Graphql; +module GraphqlTag = ApolloClient__GraphqlTag; +module FetchResult = ApolloClient__Link_Core_Types.FetchResult; +module Types = ApolloClient__Types; + +module PureQueryOptions = { + module Js_ = { + // export declare type PureQueryOptions = { + // query: DocumentNode; + // variables?: { + // [key: string]: any; + // }; + // context?: any; + // }; + type t('variables) = { + query: Graphql.documentNode, + variables: option('variables), + context: option(Js.Json.t), + }; + }; + + type t('variables) = { + query: string, + variables: option('variables), + context: option(Js.Json.t), + }; + + let toJs: t('variables) => Js_.t('variables) = + t => { + query: GraphqlTag.gql(t.query), + variables: t.variables, + context: t.context, + }; +}; + +module ApolloQueryResult = { + module Js_ = { + // export declare type ApolloQueryResult = { + // data?: T; + // errors?: ReadonlyArray; + // loading: boolean; + // networkStatus: NetworkStatus; + // }; + type t('jsData) = { + data: option('jsData), + errors: option(array(Graphql.Error.GraphQLError.t)), + loading: bool, + networkStatus: int, + }; + }; + + type t('parsedData) = Js_.t('parsedData); + + let fromJs: (t('jsData), ~parse: 'jsData => 'parsedData) => t('parsedData) = + ({data, errors, loading, networkStatus}, ~parse) => { + data: data->Belt.Option.map(parse), + errors, + loading, + networkStatus, + }; +}; + +module MutationQueryReducer = { + module Js_ = { + // export declare type MutationQueryReducer = (previousResult: Record, options: { + // mutationResult: FetchResult; + // queryName: string | undefined; + // queryVariables: Record; + // }) => Record; + type options('jsData) = { + mutationResult: FetchResult.Js_.t('jsData), + queryName: option(string), + queryVariables: Js.Json.t // ACTUAL: Record + }; + + type t('jsData) = (. Js.Json.t, options('jsData)) => Js.Json.t; + }; + + type options('data) = { + mutationResult: FetchResult.t('data), + queryName: option(string), + queryVariables: Js.Json.t // ACTUAL: Record + }; + + type t('data) = (Js.Json.t, options('data)) => Js.Json.t; + + let toJs: + (t('data), ~parse: Types.parse('jsData, 'data)) => + (. Js.Json.t, Js_.options('jsData)) => Js.Json.t = + (t, ~parse) => + (. previousResult, jsOptions) => + t( + previousResult, + { + mutationResult: + jsOptions.mutationResult->FetchResult.fromJs(~parse), + queryName: jsOptions.queryName, + queryVariables: jsOptions.queryVariables, + }, + ); +}; + +module MutationQueryReducersMap = { + module Js_ = { + // export declare type MutationQueryReducersMap = { + // [queryName: string]: MutationQueryReducer; + // }; + type t('jsData) = Js.Dict.t(MutationQueryReducer.Js_.t('jsData)); + }; + + type t('data) = Js.Dict.t(MutationQueryReducer.t('data)); + + let toJs: + (t('data), ~parse: Types.parse('jsData, 'data)) => Js_.t('jsData) = + (t, ~parse) => { + Js.Dict.map( + (. mutationQueryReducer) => + mutationQueryReducer->MutationQueryReducer.toJs(~parse), + t, + ); + }; +}; diff --git a/src/core/ApolloClient__Core_WatchQueryOptions.re b/src/core/ApolloClient__Core_WatchQueryOptions.re new file mode 100644 index 0000000..11cbcb1 --- /dev/null +++ b/src/core/ApolloClient__Core_WatchQueryOptions.re @@ -0,0 +1,236 @@ +module Cache = ApolloClient__Cache_Core_Cache; +module FetchResult = ApolloClient__Link_Core_Types.FetchResult; +module GraphQL = ApolloClient__Graphql; +module GraphqlTag = ApolloClient__Graphql; +module MutationQueryReducersMap = ApolloClient__Core_Types.MutationQueryReducersMap; +module Types = ApolloClient__Types; +module PureQueryOptions = ApolloClient__Core_Types.PureQueryOptions; + +module ErrorPolicy = { + module Js_ = { + // export declare type ErrorPolicy = 'none' | 'ignore' | 'all'; + type t = string; + }; + + type t = + | None + | Ignore + | All; + + let toJs = + fun + | None => "none" + | Ignore => "ignore" + | All => "all"; +}; + +module FetchPolicy = { + module Js_ = { + // export declare type FetchPolicy = 'cache-first' | 'network-only' | 'cache-only' | 'no-cache' | 'standby'; + type t = string; + }; + + type t = + | CacheFirst + | CacheOnly + | NetworkOnly + | NoCache + | Standby; + + let toJs = + fun + | CacheFirst => "cache-first" + | CacheOnly => "cache-only" + | NetworkOnly => "network-only" + | NoCache => "no-cache" + | Standby => "standby"; +}; + +module FetchPolicy__noCacheExtracted = { + module Js_ = { + // Extract + type t = string; + }; + type t = + | CacheFirst + | CacheOnly + | NetworkOnly + | Standby; + + let toJs = + fun + | CacheFirst => "cache-first" + | CacheOnly => "cache-only" + | NetworkOnly => "network-only" + | Standby => "standby"; +}; + +module WatchQueryFetchPolicy = { + module Js_ = { + // export declare type WatchQueryFetchPolicy = FetchPolicy | 'cache-and-network'; + type t = string; + }; + + type t = + | CacheAndNetwork + | CacheFirst + | CacheOnly + | NetworkOnly + | NoCache + | Standby; + + let toJs = + fun + | CacheAndNetwork => "cache-and-network" + | CacheFirst => "cache-first" + | CacheOnly => "cache-only" + | NetworkOnly => "network-only" + | NoCache => "no-cache" + | Standby => "standby"; +}; + +module QueryOptions = { + module Js_ = { + type t('variables) = { + fetchPolicy: option(FetchPolicy.Js_.t), + // ...extends QueryBaseOptions + query: GraphQL.Language.documentNode, + variables: option('variables), + errorPolicy: option(ErrorPolicy.Js_.t), + context: option(Js.Json.t), + }; + }; + + type t('variables) = { + fetchPolicy: option(FetchPolicy.t), + // ...extends QueryBaseOptions + query: ApolloClient__Graphql.documentNode, + variables: option('variables), + errorPolicy: option(ErrorPolicy.t), + context: option(Js.Json.t), + }; + + let toJs: t('variables) => Js_.t('variables) = + t => { + fetchPolicy: t.fetchPolicy->Belt.Option.map(FetchPolicy.toJs), + query: t.query, + variables: t.variables, + errorPolicy: t.errorPolicy->Belt.Option.map(ErrorPolicy.toJs), + context: t.context, + }; +}; + +module MutationUpdaterFn = { + module Js_ = { + type t('jsData) = (. Cache.t, FetchResult.Js_.t('jsData)) => unit; + }; + + type t('data) = (Cache.t, FetchResult.t('data)) => unit; + + let toJs: + (t('data), ~parse: Types.parse('jsData, 'data)) => Js_.t('jsData) = + (mutationUpdaterFn, ~parse) => + (. cache, jsFetchResult) => + mutationUpdaterFn(cache, jsFetchResult->FetchResult.fromJs(~parse)); +}; + +module RefetchQueryDescription = { + module Js_ = { + // CAVEAT: I did not try very hard to find a simpler alternative + module Union: { + type t; + let string: string => t; + let pureQueryOptions: PureQueryOptions.Js_.t(_) => t; + } = { + [@unboxed] + type t = + | Any('a): t; + let string = (v: string) => Any(v); + let pureQueryOptions = (v: PureQueryOptions.Js_.t(_)) => Any(v); + }; + + type t = array(Union.t); + }; + + type t_variant = + | PureQueryOptions(PureQueryOptions.t('variables)): t_variant + | String(string): t_variant; + + type t = array(t_variant); + + let toJs: t => Js_.t = + Belt.Array.map( + _, + fun + | PureQueryOptions(options) => + Js_.Union.pureQueryOptions(options->PureQueryOptions.toJs) + | String(string) => Js_.Union.string(string), + ); +}; + +module MutationOptions = { + module Js_ = { + // export interface MutationOptions extends MutationBaseOptions { + // mutation: DocumentNode; + // context?: any; + // fetchPolicy?: Extract; + // } + type t('jsData, 'variables) = { + mutation: GraphqlTag.documentNode, + context: option(Js.Json.t), + fetchPolicy: option(FetchPolicy__noCacheExtracted.Js_.t), + // ...extends MutationBaseOption, + awaitRefetchQueries: option(bool), + errorPolicy: option(ErrorPolicy.Js_.t), + optimisticResponse: option('variables => 'jsData), + update: option(MutationUpdaterFn.Js_.t('jsData)), + updateQueries: option(MutationQueryReducersMap.Js_.t('jsData)), + refetchQueries: option(RefetchQueryDescription.Js_.t), + variables: option('variables), + }; + }; + + type t('data, 'variables) = { + context: option(Js.Json.t), + fetchPolicy: option(FetchPolicy__noCacheExtracted.t), + mutation: GraphqlTag.documentNode, + // ...extends MutationBaseOption, + awaitRefetchQueries: option(bool), + errorPolicy: option(ErrorPolicy.t), + optimisticResponse: option('variables => 'data), + refetchQueries: option(RefetchQueryDescription.t), + update: option(MutationUpdaterFn.t('data)), + updateQueries: option(MutationQueryReducersMap.t('data)), + variables: option('variables), + }; + + let toJs: + ( + t('data, 'variables), + ~parse: Types.parse('jsData, 'data), + ~serialize: Types.serialize('data, 'jsData) + ) => + Js_.t('jsData, 'variables) = + (t, ~parse, ~serialize) => { + awaitRefetchQueries: t.awaitRefetchQueries, + context: t.context, + errorPolicy: t.errorPolicy->Belt.Option.map(ErrorPolicy.toJs), + fetchPolicy: + t.fetchPolicy->Belt.Option.map(FetchPolicy__noCacheExtracted.toJs), + mutation: t.mutation, + optimisticResponse: + t.optimisticResponse + ->Belt.Option.map((optimisticResponse, variables) => + optimisticResponse(variables)->serialize + ), + refetchQueries: + t.refetchQueries->Belt.Option.map(RefetchQueryDescription.toJs), + update: t.update->Belt.Option.map(MutationUpdaterFn.toJs(~parse)), + updateQueries: + t.updateQueries + ->Belt.Option.map(MutationQueryReducersMap.toJs(~parse)), + variables: t.variables, + }; +}; diff --git a/src/errors/ApolloClient__Errors.re b/src/errors/ApolloClient__Errors.re new file mode 100644 index 0000000..3701b83 --- /dev/null +++ b/src/errors/ApolloClient__Errors.re @@ -0,0 +1,38 @@ +module Graphql = ApolloClient__Graphql; +module GraphQLError = Graphql.Error.GraphQLError; + +module ApolloError = { + // export declare class ApolloError extends Error { + // constructor({ graphQLErrors, networkError, errorMessage, extraInfo, }: { + // graphQLErrors?: ReadonlyArray; + // networkError?: Error | null; + // errorMessage?: string; + // extraInfo?: any; + // }); + // } + module Js_ = { + // export declare class ApolloError extends Error { + // message: string; + // graphQLErrors: ReadonlyArray; + // networkError: Error | null; + // extraInfo: any; + // constructor({ graphQLErrors, networkError, errorMessage, extraInfo, }: { + // graphQLErrors?: ReadonlyArray; + // networkError?: Error | null; + // errorMessage?: string; + // extraInfo?: any; + // }); + // } + type t = { + extraInfo: Js.Json.t, + graphQLErrors: array(Graphql.Error.GraphQLError.t), + networkError: Js.nullable(Js.Exn.t), + // ...extends Error + name: string, + message: string, + stack: option(string), + }; + }; + + type t = Js_.t; +}; diff --git a/src/link/core/ApolloClient__Link_Core_Types.re b/src/link/core/ApolloClient__Link_Core_Types.re new file mode 100644 index 0000000..99ccf4c --- /dev/null +++ b/src/link/core/ApolloClient__Link_Core_Types.re @@ -0,0 +1,34 @@ +module GraphQLError = ApolloClient__Graphql_Error_GraphQLError; + +module FetchResult = { + module Js_ = { + // export interface FetchResult, E = Record> extends ExecutionResult { + // data?: TData | null; + // extensions?: E; + // context?: C; + // } + type t('jsData) = { + data: option('jsData), + extensions: option(Js.Json.t), // ACTUAL: Record + context: option(Js.Json.t), // ACTUAL: Record + // ...extends ExecutionResult + errors: option(GraphQLError.t), + }; + }; + + type t('data) = Js_.t('data); + + let fromJs: + (Js_.t('jsData), ~parse: ApolloClient__Types.parse('jsData, 'data)) => + t('data) = + (js, ~parse) => { + { + data: js.data->Belt.Option.map(parse), + extensions: js.extensions, + context: js.context, + errors: js.errors, + }; + }; +}; diff --git a/src/react/ApolloClient__React.re b/src/react/ApolloClient__React.re new file mode 100644 index 0000000..0ece11c --- /dev/null +++ b/src/react/ApolloClient__React.re @@ -0,0 +1,2 @@ +module Types = ApolloClient__React_Types; +let useQuery = ApolloClient__React_UseQuery.useQuery; diff --git a/src/react/hooks/ApolloClient__React_UseQuery.re b/src/react/hooks/ApolloClient__React_UseQuery.re new file mode 100644 index 0000000..7e7cf57 --- /dev/null +++ b/src/react/hooks/ApolloClient__React_UseQuery.re @@ -0,0 +1,146 @@ +module ApolloError = ApolloClient__Errors.ApolloError; +module ErrorPolicy = ApolloClient__Core_WatchQueryOptions.ErrorPolicy; +module Graphql = ApolloClient__Graphql; +module GraphqlTag = ApolloClient__GraphqlTag; +module QueryHookOptions = ApolloClient__React_Types.QueryHookOptions; +module QueryResult = ApolloClient__React_Types.QueryResult; +module WatchQueryFetchPolicy = ApolloClient__Core_WatchQueryOptions.WatchQueryFetchPolicy; + +module type Operation = ApolloClient__Types.Operation; + +type simpleQueryResult('a) = + | Data('a) + | Error(ApolloError.t) + | Loading + | NoData; + +module Js_ = { + // export declare function useQuery(query: DocumentNode, options?: QueryHookOptions): QueryResult; + [@bs.module "@apollo/client"] + external useQuery: + ( + ~query: Graphql.documentNode, + ~options: QueryHookOptions.Js_.t('jsData, 'variables)=? + ) => + QueryResult.Js_.t('jsData, 'variables) = + "useQuery"; +}; + +let useQuery: + type data variables jsData jsVariables. + ( + ~client: ApolloClient__ApolloClient.t=?, + ~context: Js.Json.t=?, + ~displayName: string=?, + ~errorPolicy: ErrorPolicy.t=?, + ~fetchPolicy: WatchQueryFetchPolicy.t=?, + ~notifyOnNetworkStatusChange: bool=?, + ~onCompleted: jsData => unit=?, + ~onError: ApolloError.t => unit=?, + ~partialRefetch: bool=?, + ~pollInterval: int=?, + ~skip: bool=?, + ~ssr: bool=?, + ~variables: variables=?, + (module Operation with + type t = data and + type Raw.t = jsData and + type Raw.t_variables = jsVariables) + ) => + (simpleQueryResult(data), QueryResult.t(data, variables)) = + ( + ~client=?, + ~context=?, + ~displayName=?, + ~errorPolicy=?, + ~fetchPolicy=?, + ~notifyOnNetworkStatusChange=?, + ~onCompleted=?, + ~onError=?, + ~partialRefetch=?, + ~pollInterval=?, + ~skip=?, + ~ssr=?, + ~variables=?, + (module Definition), + ) => { + let jsQueryResult = + Js_.useQuery( + ~query=GraphqlTag.gql(Definition.query), + ~options= + QueryHookOptions.toJs({ + client, + context, + displayName, + errorPolicy, + fetchPolicy, + onCompleted, + onError, + notifyOnNetworkStatusChange, + partialRefetch, + pollInterval, + query: None, + skip, + ssr, + variables, + }), + ); + + ApolloClient__Utils.useGuaranteedMemo1( + () => { + let queryResult = + jsQueryResult->QueryResult.fromJs( + ~parse=Definition.parse, + ~serialize=Definition.serialize, + ); + + let simple = + switch (queryResult) { + | {loading: true} => Loading + | {error: Some(error)} => Error(error) + | {data: Some(data)} => Data(data) + | _ => NoData + }; + + (simple, queryResult); + }, + jsQueryResult, + ); + }; + +module Extend = (M: Operation) => { + let use = + ( + ~client=?, + ~context=?, + ~displayName=?, + ~errorPolicy=?, + ~fetchPolicy=?, + ~notifyOnNetworkStatusChange=?, + ~onCompleted=?, + ~onError=?, + ~partialRefetch=?, + ~pollInterval=?, + ~skip=?, + ~ssr=?, + ~variables=?, + (), + ) => { + useQuery( + ~client?, + ~context?, + ~displayName?, + ~errorPolicy?, + ~fetchPolicy?, + ~notifyOnNetworkStatusChange?, + ~onCompleted?, + ~onError?, + ~partialRefetch?, + ~pollInterval?, + ~skip?, + ~ssr?, + ~variables?, + (module M), + ); + }; +}; diff --git a/src/react/hooks/ApolloClient__React_UseSubscription.re b/src/react/hooks/ApolloClient__React_UseSubscription.re new file mode 100644 index 0000000..f6e8e18 --- /dev/null +++ b/src/react/hooks/ApolloClient__React_UseSubscription.re @@ -0,0 +1,122 @@ +module ApolloError = ApolloClient__Errors.ApolloError; +module BaseSubscriptionOptions = ApolloClient__React_Types.BaseSubscriptionOptions; +module FetchPolicy = ApolloClient__Core_WatchQueryOptions.FetchPolicy; +module Graphql = ApolloClient__Graphql; +module GraphqlTag = ApolloClient__GraphqlTag; +module OnSubscriptionDataOptions = ApolloClient__React_Types.OnSubscriptionDataOptions; +module SubscriptionHookOptions = ApolloClient__React_Types.SubscriptionHookOptions; + +module type Operation = ApolloClient__Types.Operation; + +type simpleQueryResult('a) = + | Data('a) + | Error(ApolloError.t) + | Loading + | NoData; + +module Js_ = { + type useSubscription_result('jsData, 'variables) = { + variables: option('variables), + loading: bool, + data: option('jsData), + error: option(ApolloError.Js_.t), + }; + + // export declare function useSubscription(subscription: DocumentNode, options?: SubscriptionHookOptions): { + // variables: TVariables | undefined; + // loading: boolean; + // data?: TData | undefined; + // error?: import("../..").ApolloError | undefined; + // }; + [@bs.module "@apollo/client"] + external useSubscription: + ( + ~subscription: Graphql.Language.documentNode, + ~options: SubscriptionHookOptions.Js_.t('jsData, 'variables)=? + ) => + useSubscription_result('jsData, 'variables) = + "useSubscription"; +}; + +let useSubscription: + type data variables jsData jsVariables. + ( + ~client: ApolloClient__ApolloClient.t=?, + ~fetchPolicy: FetchPolicy.t=?, + ~onSubscriptionData: OnSubscriptionDataOptions.t(data) => unit=?, + ~onSubscriptionComplete: unit => unit=?, + ~shouldResubscribe: BaseSubscriptionOptions.t(data, variables) => bool=?, + ~skip: bool=?, + ~variables: variables=?, + (module Operation with + type t = data and + type Raw.t = jsData and + type Raw.t_variables = jsVariables) + ) => + simpleQueryResult(data) = + ( + ~client=?, + ~fetchPolicy=?, + ~onSubscriptionData=?, + ~onSubscriptionComplete=?, + ~shouldResubscribe=?, + ~skip=?, + ~variables=?, + (module Definition), + ) => { + let jsSubscriptionResult = + Js_.useSubscription( + ~subscription=GraphqlTag.gql(Definition.query), + ~options= + SubscriptionHookOptions.toJs( + { + client, + fetchPolicy, + onSubscriptionData, + onSubscriptionComplete, + subscription: None, + shouldResubscribe, + skip, + variables, + }, + ~parse=Definition.parse, + ), + ); + + ApolloClient__Utils.useGuaranteedMemo1( + () => { + switch (jsSubscriptionResult) { + | {loading: true} => Loading + | {error: Some(error)} => Error(error) + | {data: Some(data)} => Data(data->Definition.parse) + | _ => NoData + } + }, + jsSubscriptionResult, + ); + }; + +module Extend = (M: Operation) => { + let use = + ( + ~client=?, + ~fetchPolicy=?, + ~onSubscriptionData=?, + ~onSubscriptionComplete=?, + ~shouldResubscribe=?, + ~skip=?, + ~variables=?, + (), + ) => { + useSubscription( + ~client?, + ~fetchPolicy?, + ~onSubscriptionData?, + ~onSubscriptionComplete?, + ~shouldResubscribe?, + ~skip?, + ~variables?, + (module M), + ); + }; +}; diff --git a/src/react/types/ApolloClient__React_Types.re b/src/react/types/ApolloClient__React_Types.re new file mode 100644 index 0000000..da113be --- /dev/null +++ b/src/react/types/ApolloClient__React_Types.re @@ -0,0 +1,345 @@ +module ApolloError = ApolloClient__Errors.ApolloError; +module Core = ApolloClient__Core; +module Errors = ApolloClient__Errors; +module FetchPolicy = ApolloClient__Core_WatchQueryOptions.FetchPolicy; +module Graphql = ApolloClient__Graphql; + +module QueryHookOptions = { + module Js_ = { + // export interface QueryHookOptions extends QueryFunctionOptions { + // query?: DocumentNode; + // } + type t('jsData, 'variables) = { + query: option(Graphql.documentNode), + // ...extends QueryFunctionOptions + displayName: option(string), + skip: option(bool), + onCompleted: option('jsData => unit), + onError: option(Errors.ApolloError.t => unit), + // ..extends BaseQueryOptions + client: option(ApolloClient__ApolloClient.t), + context: option(Js.Json.t), // ACTUAL: Record + errorPolicy: option(string), + fetchPolicy: option(string), + notifyOnNetworkStatusChange: option(bool), + partialRefetch: option(bool), + pollInterval: option(int), + // INTENTIONALLY IGNORED + // returnPartialData: option(bool), + ssr: option(bool), + variables: option('variables), + }; + }; + + type t('jsData, 'variables) = { + query: option(Graphql.documentNode), + // ...extends QueryFunctionOptions + displayName: option(string), + skip: option(bool), + // consider parsing? + onCompleted: option('jsData => unit), + onError: option(Errors.ApolloError.t => unit), + // ...extends BaseQueryOptions + client: option(ApolloClient__ApolloClient.t), + context: option(Js.Json.t), + errorPolicy: option(Core.WatchQueryOptions.ErrorPolicy.t), + fetchPolicy: option(Core.WatchQueryOptions.WatchQueryFetchPolicy.t), + notifyOnNetworkStatusChange: option(bool), + partialRefetch: option(bool), + pollInterval: option(int), + // INTENTIONALLY IGNORED + // returnPartialData: option(bool), + ssr: option(bool), + variables: option('variables), + }; + + let toJs = (t: t(_, _)): Js_.t(_, _) => { + client: t.client, + context: t.context, + displayName: t.displayName, + errorPolicy: + t.errorPolicy->Belt.Option.map(Core.WatchQueryOptions.ErrorPolicy.toJs), + onCompleted: t.onCompleted, + onError: t.onError, + fetchPolicy: + t.fetchPolicy + ->Belt.Option.map(Core.WatchQueryOptions.WatchQueryFetchPolicy.toJs), + notifyOnNetworkStatusChange: t.notifyOnNetworkStatusChange, + query: t.query, + pollInterval: t.pollInterval, + partialRefetch: t.partialRefetch, + skip: t.skip, + ssr: t.ssr, + variables: t.variables, + }; +}; + +module QueryResult = { + module Js_ = { + type t_fetchMoreOptions_updateQueryOptions('parsedData, 'variables) = { + fetchMoreResult: option('parsedData), + variables: option('variables), + }; + + type t_fetchMoreOptions('jsData, 'variables) = { + query: option(Graphql.Language.documentNode), + variables: option('variables), + context: option(Js.Json.t), + updateQuery: + ( + 'jsData, + t_fetchMoreOptions_updateQueryOptions('jsData, 'variables) + ) => + 'jsData, + }; + + // export interface QueryResult extends ObservableQueryFields { + // client: ApolloClient; + // data: TData | undefined; + // error?: ApolloError; + // loading: boolean; + // networkStatus: NetworkStatus; + // called: true; + // } + type t('jsData, 'variables) = { + fetchMore: + t_fetchMoreOptions('jsData, 'variables) => + Js.Promise.t(Core.Types.ApolloQueryResult.t('jsData)), + called: bool, + client: ApolloClient__ApolloClient.t, + data: option('jsData), + error: option(Errors.ApolloError.t), + loading: bool, + networkStatus: Core.NetworkStatus.t, + }; + }; + + type t('parsedData, 'variables) = { + called: bool, + client: ApolloClient__ApolloClient.t, + data: option('parsedData), + error: option(Errors.ApolloError.t), + fetchMore: + ( + ~context: Js.Json.t=?, + ~variables: 'variables=?, + ~updateQuery: ( + 'parsedData, + Js_.t_fetchMoreOptions_updateQueryOptions( + 'parsedData, + 'variables, + ) + ) => + 'parsedData, + unit + ) => + Js.Promise.t(Core.Types.ApolloQueryResult.t('parsedData)), + loading: bool, + networkStatus: Core.NetworkStatus.t, + }; + + let fromJs: + ( + Js_.t('jsData, 'variables), + ~parse: 'jsData => 'parsedData, + ~serialize: 'parsedData => 'jsData + ) => + t('parsedData, 'variables) = + (js, ~parse, ~serialize) => { + called: js.called, + client: js.client, + data: js.data->Belt.Option.map(parse), + error: js.error, + fetchMore: + (~context=?, ~variables=?, ~updateQuery as jsUpdateQuery, ()) => { + js.fetchMore({ + context, + query: None, + updateQuery: (previousResult, {fetchMoreResult, variables}) => + jsUpdateQuery( + parse(previousResult), + { + fetchMoreResult: fetchMoreResult->Belt.Option.map(parse), + variables, + }, + ) + ->serialize, + variables, + }) + ->Js.Promise.then_( + jsResult => + Js.Promise.resolve( + Core.Types.ApolloQueryResult.fromJs(jsResult, ~parse), + ), + _, + ); + }, + loading: js.loading, + networkStatus: js.networkStatus, + }; +}; + +module SubscriptionResult = { + module Js_ = { + // export interface SubscriptionResult { + // loading: boolean; + // data?: TData; + // error?: ApolloError; + // } + type t('jsData) = { + loading: bool, + data: option('jsData), + error: option(ApolloError.Js_.t), + }; + }; + + type t('data) = { + loading: bool, + data: option('data), + error: option(ApolloError.Js_.t), + }; + + let fromJs: (Js_.t('jsData), ~parse: 'jsData => 'data) => t('data) = + (js, ~parse) => { + loading: js.loading, + data: js.data->Belt.Option.map(parse), + error: js.error, + }; +}; + +module OnSubscriptionDataOptions = { + module Js_ = { + // export interface OnSubscriptionDataOptions { + // client: ApolloClient; + // subscriptionData: SubscriptionResult; + // } + type t('jsData) = { + client: ApolloClient__ApolloClient.t, + subscriptionData: SubscriptionResult.Js_.t('jsData), + }; + }; + + type t('data) = { + client: ApolloClient__ApolloClient.t, + subscriptionData: SubscriptionResult.t('data), + }; + + let fromJs: (Js_.t('jsData), ~parse: 'jsData => 'data) => t('data) = + (js, ~parse) => { + client: js.client, + subscriptionData: + js.subscriptionData->SubscriptionResult.fromJs(~parse), + }; +}; + +module BaseSubscriptionOptions = { + module Js_ = { + // export interface BaseSubscriptionOptions { + // variables?: TVariables; + // fetchPolicy?: FetchPolicy; + // shouldResubscribe?: boolean | ((options: BaseSubscriptionOptions) => boolean); + // client?: ApolloClient; + // skip?: boolean; + // onSubscriptionData?: (options: OnSubscriptionDataOptions) => any; + // onSubscriptionComplete?: () => void; + // } + type t('jsData, 'variables) = { + variables: option('variables), + fetchPolicy: option(FetchPolicy.t), + shouldResubscribe: option((. t('jsData, 'variables)) => bool), + client: option(ApolloClient__ApolloClient.t), + skip: option(bool), + onSubscriptionData: + option((. OnSubscriptionDataOptions.Js_.t('jsData)) => unit), + onSubscriptionComplete: option(unit => unit), + }; + }; + + type t('data, 'variables) = { + variables: option('variables), + fetchPolicy: option(FetchPolicy.t), + shouldResubscribe: option(t('data, 'variables) => bool), + client: option(ApolloClient__ApolloClient.t), + skip: option(bool), + onSubscriptionData: option(OnSubscriptionDataOptions.t('data) => unit), + onSubscriptionComplete: option(unit => unit), + }; + + let fromJs: Js_.t('jsData, 'variables) => t('data, 'variables) = + js => { + variables: js.variables, + fetchPolicy: js.fetchPolicy, + // shouldResubscribe: what to do here? + shouldResubscribe: Obj.magic(js.shouldResubscribe), + client: js.client, + skip: js.skip, + // onSubscriptionData: what to do here? + onSubscriptionData: Obj.magic(js.onSubscriptionData), + onSubscriptionComplete: js.onSubscriptionComplete, + }; +}; + +module SubscriptionHookOptions = { + module Js_ = { + // export interface SubscriptionHookOptions extends BaseSubscriptionOptions { + // subscription?: DocumentNode; + // } + type t('jsData, 'variables) = { + subscription: option(Graphql.documentNode), + // ...extends BaseSubscriptionOptions + variables: option('variables), + fetchPolicy: option(FetchPolicy.t), + shouldResubscribe: + option( + (. BaseSubscriptionOptions.Js_.t('jsData, 'variables)) => bool, + ), + client: option(ApolloClient__ApolloClient.t), + skip: option(bool), + onSubscriptionData: + option((. OnSubscriptionDataOptions.Js_.t('jsData)) => unit), + onSubscriptionComplete: option(unit => unit), + }; + }; + + type t('data, 'variables) = { + subscription: option(Graphql.documentNode), + variables: option('variables), + fetchPolicy: option(FetchPolicy.t), + shouldResubscribe: + option(BaseSubscriptionOptions.t('data, 'variables) => bool), + client: option(ApolloClient__ApolloClient.t), + skip: option(bool), + onSubscriptionData: option(OnSubscriptionDataOptions.t('data) => unit), + onSubscriptionComplete: option(unit => unit), + }; + + let toJs: + (t('data, 'variables), ~parse: 'jsData => 'data) => + Js_.t('jsData, 'variables) = + (t, ~parse) => { + subscription: t.subscription, + variables: t.variables, + fetchPolicy: t.fetchPolicy, + shouldResubscribe: + t.shouldResubscribe + ->Belt.Option.map(shouldResubscribe => + (. jsBaseSubscriptionOptions) => + shouldResubscribe( + jsBaseSubscriptionOptions->BaseSubscriptionOptions.fromJs, + ) + ), + client: t.client, + skip: t.skip, + onSubscriptionData: + t.onSubscriptionData + ->Belt.Option.map(onSubscriptionData => + (. jsOnSubscriptionDataOptions) => + onSubscriptionData( + jsOnSubscriptionDataOptions->OnSubscriptionDataOptions.fromJs( + ~parse, + ), + ) + ), + onSubscriptionComplete: t.onSubscriptionComplete, + }; +}; From 7c6b25778d04ed992aaa72853e2c74ddd3dc0708 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sat, 23 May 2020 21:28:20 -0500 Subject: [PATCH 07/21] fix: missed serialize in writeData --- src/ApolloClient__ApolloClient.re | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re index 0c51d77..3df2f3e 100644 --- a/src/ApolloClient__ApolloClient.re +++ b/src/ApolloClient__ApolloClient.re @@ -260,7 +260,7 @@ let writeQuery: client, ~options={ broadcast, - data, + data: data->Definition.serialize, id, query: GraphqlTag.gql(Definition.query), variables, From 98675f95cd31dc2855d3ed5d7b180c612d44ca3c Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sat, 23 May 2020 22:12:28 -0500 Subject: [PATCH 08/21] refactor: add ApolloClient to main module --- src/ApolloClient.re | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ApolloClient.re b/src/ApolloClient.re index a1227a8..afa48dd 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -16,7 +16,6 @@ // export { fromError } from './link/utils/fromError.js'; // export { createHttpLink } from './link/http/createHttpLink.js'; // export { HttpLink } from './link/http/HttpLink.js'; -// export { ApolloClient } from './ApolloClient.js'; // export { ApolloCache } from './cache/core/cache.js'; // export { Cache } from './cache/core/types/Cache.js'; // export { MissingFieldError } from './cache/core/types/common.js'; @@ -38,10 +37,12 @@ // export { useApolloClient } from './react/hooks/useApolloClient.js'; // export { RenderPromises } from './react/ssr/RenderPromises.js'; -let useQuery = ApolloClient__React_UseQuery.useQuery; -let useSubscription = ApolloClient__React_UseSubscription.useSubscription; +module ApolloClient = ApolloClient__ApolloClient; module Extend = { module Query = ApolloClient__React_UseQuery.Extend; module Subscription = ApolloClient__React_UseSubscription.Extend; }; + +let useQuery = ApolloClient__React_UseQuery.useQuery; +let useSubscription = ApolloClient__React_UseSubscription.useSubscription; From 4a69308aa8e70fa3cbc96fbb3e66b709611d7499 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Tue, 26 May 2020 18:08:14 -0500 Subject: [PATCH 09/21] refactor: add ApolloProvider, CONTRIBUTING file, and some cleanup --- CONTRIBUTING.md | 98 +++++++++++++++++++ src/ApolloClient.re | 1 + src/errors/ApolloClient__ApolloError.re | 30 ++++++ src/errors/ApolloClient__Errors.re | 38 ------- .../core/ApolloClient__Link_Core_Types.re | 8 +- src/react/ApolloClient__React.re | 3 + .../ApolloClient__React_ApolloProvider.re | 10 ++ .../hooks/ApolloClient__React_UseQuery.re | 60 +++++------- .../ApolloClient__React_UseSubscription.re | 32 +++--- src/react/types/ApolloClient__React_Types.re | 51 +++++----- 10 files changed, 217 insertions(+), 114 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 src/errors/ApolloClient__ApolloError.re delete mode 100644 src/errors/ApolloClient__Errors.re create mode 100644 src/react/ApolloClient__React_ApolloProvider.re diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..023d4d0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,98 @@ +NOTE: this is just documenting my process for this PR in case anyone wants to help. It's not necessarily intended to be used as the CONTRIBUTING file for `reason-apollo-hooks` + +# Goals and Intent + +My hope is that we can achieve well maintained, nearly-complete bindings without a huge burden on any single person if we follow these two rules: + +1. Follow a consistent pattern for bindings +1. No partial types or bindings if possible + +Let's try it and see how it works out! + +## Going the Full Distance + +No single binding is _that_ much work. Please completely type something as you come across it or leave it for someone else. If all of us contribute just a little piece, but do it completely, it should be very easy to get 99% complete bindings. Also, 50% of the work is in tracing through the code and loading up context. This way no one has to go back and duplicate that work. Each binding we add also makes the next one that much faster as we have more and more types we can reuse blindly. + +# Guidelines (style) + +## Module Names + +``` +@apollo/client/react/hooks/react/useQuery.js +``` + +should become + +``` +reason-react-hooks/src/react/hooks/ApolloClient__React_UseQuery.re +``` + +in reason. + +### Breaking it down: `/[1]/[2]__[3]_[4]` + +1. Modules should be located in the same directory structure as the js counterpart (usually there is a `.d.ts` for every `.js` file so we can think of them interchangeably) +1. All module names should be prefixed with `ApolloClient__` "namespace" +1. Modules should be prefixed with the nearest `.js` parent module (and exported from there as well) +1. Modules should be named the same as the js counterpart + +## Types + +- Every type goes in its own module with a `type t` (exception: see SubStypes) +- Every type module should contain a `type t`, a `Js_` module with a `type t`, and a `toJs` or `fromJs` conversion function. `t => Js_.t` or `Js_.t => t` +- Paste the type definition from the `.d.ts` file above the `type t` in the `Js_` module +- If data requires parsing/serializing create a new record even if the shape is the same. This ensures you don't forget to parse somewhere. +- Prefer single types when the more complicated type in a union can express both `shouldResubscribe?: boolean | ((options: BaseSubscriptionOptions) => boolean);` +- Do all of this even if it doesn't need it (See Reasoning Behind `Js_` modules) + +Example: + +``` +// #1 - create a Js_ module for your type +module Js_ = { + // #2 - paste the definition from the .js file here + // #3 - add the `.js` representation of type t = ... +} + +// #4 - add the Reason representation of type t +// #4a - you can use `type t = Js_.t` if they are _exactly_ the same +// #4b - if they are the exact same _shape_ but requires parsing or serializing, *define a new record of the same shape* so we can leverage the fact that records are nominally typed to prevent someone forgetting to convert somewhere + +// #5 - add `toJs` or `fromJs`. They often require parsing: `let fromJs: Js_.t('jsData, ~parse: 'jsData => 'data) => t('data)` +``` + +### Reasoning behind `Js_` modules + +When I'm defining a `Js_` `type t` that references other types, I know I should always be using the `Js_.t` versions of those types and it's very easy to visually confirm the correct types are being referenced. The same goes for defining a top-level `type t`, I should never see a `Js_.t` there. Now I can just follow the compiler errors. + +FWIW, I tried `JS` naming, but I would accidentally type `Js` all the time and not see it. Additionally, due to the importance of the above, I wanted it to stick out and the `_` helps a little there. :shrug: + +### SubTypes + +Sometimes multiple types were required to represent a single type in TypeScript. In order to help make it clear what is a binding to an actual type and what is just needed by Reason. In this case we take a similar naming approach to the modules (prefixing with the parent). For instance, `Apollo_Client__React_Types.QueryResult.Raw` has a `type t` that uses `t_fetchMoreOptions` which in turn uses `t_fetchMoreOptions_updateQueryOptions`. + +## Binding to Js Module Exports + +`externals` go under a `Js_` module and any types they reference should be `Js_.t` versions. + +## Binding to Methods + +Prefer T-first with `[@bs.send]`. Again, `externals` go under a `Js_` module with a `type t` and any types they reference should be `Js_.t` versions. + +## Binding to Objects + +Use records + +## Binding to Enums + +Use standard variants. You can use `jsConverter` for ints, but otherwise use manual `toJs` and `fromJs` functions. + +## General + +- Prefer T-first because that's the Reason community default +- Hooks are T-last because that makes sense given their usage +- ApolloClient methods are a Frankenstein T-first _and_ T-last because they want to maintain similarity with hooks api, but are also T-first due to [@bs.send] and T-first preference + +# Exeptional Exception Handling + +TBD diff --git a/src/ApolloClient.re b/src/ApolloClient.re index afa48dd..54adac2 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -38,6 +38,7 @@ // export { RenderPromises } from './react/ssr/RenderPromises.js'; module ApolloClient = ApolloClient__ApolloClient; +module ApolloProvider = ApolloClient__React_ApolloProvider; module Extend = { module Query = ApolloClient__React_UseQuery.Extend; diff --git a/src/errors/ApolloClient__ApolloError.re b/src/errors/ApolloClient__ApolloError.re new file mode 100644 index 0000000..1c37db8 --- /dev/null +++ b/src/errors/ApolloClient__ApolloError.re @@ -0,0 +1,30 @@ +module Graphql = ApolloClient__Graphql; +module GraphQLError = Graphql.Error.GraphQLError; + +// export declare class ApolloError extends Error { +// constructor({ graphQLErrors, networkError, errorMessage, extraInfo, }: { +// graphQLErrors?: ReadonlyArray; +// networkError?: Error | null; +// errorMessage?: string; +// extraInfo?: any; +// }); +// } +module Js_ = { + // export declare class ApolloError extends Error { + // message: string; + // graphQLErrors: ReadonlyArray; + // networkError: Error | null; + // extraInfo: any; + // } + type t = { + extraInfo: Js.Json.t, + graphQLErrors: array(Graphql.Error.GraphQLError.t), + networkError: Js.nullable(Js.Exn.t), + // ...extends Error + name: string, + message: string, + stack: option(string), + }; +}; + +type t = Js_.t; diff --git a/src/errors/ApolloClient__Errors.re b/src/errors/ApolloClient__Errors.re deleted file mode 100644 index 3701b83..0000000 --- a/src/errors/ApolloClient__Errors.re +++ /dev/null @@ -1,38 +0,0 @@ -module Graphql = ApolloClient__Graphql; -module GraphQLError = Graphql.Error.GraphQLError; - -module ApolloError = { - // export declare class ApolloError extends Error { - // constructor({ graphQLErrors, networkError, errorMessage, extraInfo, }: { - // graphQLErrors?: ReadonlyArray; - // networkError?: Error | null; - // errorMessage?: string; - // extraInfo?: any; - // }); - // } - module Js_ = { - // export declare class ApolloError extends Error { - // message: string; - // graphQLErrors: ReadonlyArray; - // networkError: Error | null; - // extraInfo: any; - // constructor({ graphQLErrors, networkError, errorMessage, extraInfo, }: { - // graphQLErrors?: ReadonlyArray; - // networkError?: Error | null; - // errorMessage?: string; - // extraInfo?: any; - // }); - // } - type t = { - extraInfo: Js.Json.t, - graphQLErrors: array(Graphql.Error.GraphQLError.t), - networkError: Js.nullable(Js.Exn.t), - // ...extends Error - name: string, - message: string, - stack: option(string), - }; - }; - - type t = Js_.t; -}; diff --git a/src/link/core/ApolloClient__Link_Core_Types.re b/src/link/core/ApolloClient__Link_Core_Types.re index 99ccf4c..3447518 100644 --- a/src/link/core/ApolloClient__Link_Core_Types.re +++ b/src/link/core/ApolloClient__Link_Core_Types.re @@ -18,7 +18,13 @@ module FetchResult = { }; }; - type t('data) = Js_.t('data); + type t('data) = { + data: option('data), + extensions: option(Js.Json.t), // ACTUAL: Record + context: option(Js.Json.t), // ACTUAL: Record + // ...extends ExecutionResult + errors: option(GraphQLError.t), + }; let fromJs: (Js_.t('jsData), ~parse: ApolloClient__Types.parse('jsData, 'data)) => diff --git a/src/react/ApolloClient__React.re b/src/react/ApolloClient__React.re index 0ece11c..568d7e1 100644 --- a/src/react/ApolloClient__React.re +++ b/src/react/ApolloClient__React.re @@ -1,2 +1,5 @@ +module ApolloProvider = ApolloClient__React_ApolloProvider; module Types = ApolloClient__React_Types; + let useQuery = ApolloClient__React_UseQuery.useQuery; +let useSubscription = ApolloClient__React_UseSubscription.useSubscription; diff --git a/src/react/ApolloClient__React_ApolloProvider.re b/src/react/ApolloClient__React_ApolloProvider.re new file mode 100644 index 0000000..df1ef67 --- /dev/null +++ b/src/react/ApolloClient__React_ApolloProvider.re @@ -0,0 +1,10 @@ +// export interface ApolloProviderProps { +// client: ApolloClient; +// children: React.ReactNode | React.ReactNode[] | null; +// } +// export declare const ApolloProvider: React.FC>; +[@bs.module "@apollo/client"] +external make: + (~client: ApolloClient__ApolloClient.t, ~children: React.element) => + React.element = + "ApolloProvider"; diff --git a/src/react/hooks/ApolloClient__React_UseQuery.re b/src/react/hooks/ApolloClient__React_UseQuery.re index 7e7cf57..ee409a7 100644 --- a/src/react/hooks/ApolloClient__React_UseQuery.re +++ b/src/react/hooks/ApolloClient__React_UseQuery.re @@ -1,4 +1,4 @@ -module ApolloError = ApolloClient__Errors.ApolloError; +module ApolloError = ApolloClient__ApolloError; module ErrorPolicy = ApolloClient__Core_WatchQueryOptions.ErrorPolicy; module Graphql = ApolloClient__Graphql; module GraphqlTag = ApolloClient__GraphqlTag; @@ -35,7 +35,7 @@ let useQuery: ~errorPolicy: ErrorPolicy.t=?, ~fetchPolicy: WatchQueryFetchPolicy.t=?, ~notifyOnNetworkStatusChange: bool=?, - ~onCompleted: jsData => unit=?, + ~onCompleted: data => unit=?, ~onError: ApolloError.t => unit=?, ~partialRefetch: bool=?, ~pollInterval: int=?, @@ -47,7 +47,7 @@ let useQuery: type Raw.t = jsData and type Raw.t_variables = jsVariables) ) => - (simpleQueryResult(data), QueryResult.t(data, variables)) = + QueryResult.t(data, variables) = ( ~client=?, ~context=?, @@ -68,41 +68,33 @@ let useQuery: Js_.useQuery( ~query=GraphqlTag.gql(Definition.query), ~options= - QueryHookOptions.toJs({ - client, - context, - displayName, - errorPolicy, - fetchPolicy, - onCompleted, - onError, - notifyOnNetworkStatusChange, - partialRefetch, - pollInterval, - query: None, - skip, - ssr, - variables, - }), + QueryHookOptions.toJs( + { + client, + context, + displayName, + errorPolicy, + fetchPolicy, + onCompleted, + onError, + notifyOnNetworkStatusChange, + partialRefetch, + pollInterval, + query: None, + skip, + ssr, + variables, + }, + ~parse=Definition.parse, + ), ); ApolloClient__Utils.useGuaranteedMemo1( () => { - let queryResult = - jsQueryResult->QueryResult.fromJs( - ~parse=Definition.parse, - ~serialize=Definition.serialize, - ); - - let simple = - switch (queryResult) { - | {loading: true} => Loading - | {error: Some(error)} => Error(error) - | {data: Some(data)} => Data(data) - | _ => NoData - }; - - (simple, queryResult); + jsQueryResult->QueryResult.fromJs( + ~parse=Definition.parse, + ~serialize=Definition.serialize, + ) }, jsQueryResult, ); diff --git a/src/react/hooks/ApolloClient__React_UseSubscription.re b/src/react/hooks/ApolloClient__React_UseSubscription.re index f6e8e18..1557099 100644 --- a/src/react/hooks/ApolloClient__React_UseSubscription.re +++ b/src/react/hooks/ApolloClient__React_UseSubscription.re @@ -1,4 +1,4 @@ -module ApolloError = ApolloClient__Errors.ApolloError; +module ApolloError = ApolloClient__ApolloError; module BaseSubscriptionOptions = ApolloClient__React_Types.BaseSubscriptionOptions; module FetchPolicy = ApolloClient__Core_WatchQueryOptions.FetchPolicy; module Graphql = ApolloClient__Graphql; @@ -8,12 +8,6 @@ module SubscriptionHookOptions = ApolloClient__React_Types.SubscriptionHookOptio module type Operation = ApolloClient__Types.Operation; -type simpleQueryResult('a) = - | Data('a) - | Error(ApolloError.t) - | Loading - | NoData; - module Js_ = { type useSubscription_result('jsData, 'variables) = { variables: option('variables), @@ -38,6 +32,13 @@ module Js_ = { "useSubscription"; }; +type useSubscription_result('data, 'variables) = { + variables: option('variables), + loading: bool, + data: option('data), + error: option(ApolloError.Js_.t), +}; + let useSubscription: type data variables jsData jsVariables. ( @@ -53,7 +54,7 @@ let useSubscription: type Raw.t = jsData and type Raw.t_variables = jsVariables) ) => - simpleQueryResult(data) = + useSubscription_result(data, variables) = ( ~client=?, ~fetchPolicy=?, @@ -84,14 +85,13 @@ let useSubscription: ); ApolloClient__Utils.useGuaranteedMemo1( - () => { - switch (jsSubscriptionResult) { - | {loading: true} => Loading - | {error: Some(error)} => Error(error) - | {data: Some(data)} => Data(data->Definition.parse) - | _ => NoData - } - }, + () => + { + variables: jsSubscriptionResult.variables, + loading: jsSubscriptionResult.loading, + data: jsSubscriptionResult.data->Belt.Option.map(Definition.parse), + error: jsSubscriptionResult.error, + }, jsSubscriptionResult, ); }; diff --git a/src/react/types/ApolloClient__React_Types.re b/src/react/types/ApolloClient__React_Types.re index da113be..bee7b51 100644 --- a/src/react/types/ApolloClient__React_Types.re +++ b/src/react/types/ApolloClient__React_Types.re @@ -1,8 +1,10 @@ -module ApolloError = ApolloClient__Errors.ApolloError; -module Core = ApolloClient__Core; -module Errors = ApolloClient__Errors; +module ApolloError = ApolloClient__ApolloError; +module ApolloQueryResult = ApolloClient__Core_Types.ApolloQueryResult; +module ErrorPolicy = ApolloClient__Core_WatchQueryOptions.ErrorPolicy; module FetchPolicy = ApolloClient__Core_WatchQueryOptions.FetchPolicy; module Graphql = ApolloClient__Graphql; +module NetworkStatus = ApolloClient__Core_NetworkStatus; +module WatchQueryFetchPolicy = ApolloClient__Core_WatchQueryOptions.WatchQueryFetchPolicy; module QueryHookOptions = { module Js_ = { @@ -15,7 +17,7 @@ module QueryHookOptions = { displayName: option(string), skip: option(bool), onCompleted: option('jsData => unit), - onError: option(Errors.ApolloError.t => unit), + onError: option(ApolloError.t => unit), // ..extends BaseQueryOptions client: option(ApolloClient__ApolloClient.t), context: option(Js.Json.t), // ACTUAL: Record @@ -31,19 +33,19 @@ module QueryHookOptions = { }; }; - type t('jsData, 'variables) = { + type t('data, 'variables) = { query: option(Graphql.documentNode), // ...extends QueryFunctionOptions displayName: option(string), skip: option(bool), // consider parsing? - onCompleted: option('jsData => unit), - onError: option(Errors.ApolloError.t => unit), + onCompleted: option('data => unit), + onError: option(ApolloError.t => unit), // ...extends BaseQueryOptions client: option(ApolloClient__ApolloClient.t), context: option(Js.Json.t), - errorPolicy: option(Core.WatchQueryOptions.ErrorPolicy.t), - fetchPolicy: option(Core.WatchQueryOptions.WatchQueryFetchPolicy.t), + errorPolicy: option(ErrorPolicy.t), + fetchPolicy: option(WatchQueryFetchPolicy.t), notifyOnNetworkStatusChange: option(bool), partialRefetch: option(bool), pollInterval: option(int), @@ -53,17 +55,18 @@ module QueryHookOptions = { variables: option('variables), }; - let toJs = (t: t(_, _)): Js_.t(_, _) => { + let toJs = + (t: t('data, 'variables), ~parse: 'jsData => 'data) + : Js_.t('jsData, 'variables) => { client: t.client, context: t.context, displayName: t.displayName, - errorPolicy: - t.errorPolicy->Belt.Option.map(Core.WatchQueryOptions.ErrorPolicy.toJs), - onCompleted: t.onCompleted, + errorPolicy: t.errorPolicy->Belt.Option.map(ErrorPolicy.toJs), + onCompleted: + t.onCompleted + ->Belt.Option.map((onCompleted, jsData) => onCompleted(jsData->parse)), onError: t.onError, - fetchPolicy: - t.fetchPolicy - ->Belt.Option.map(Core.WatchQueryOptions.WatchQueryFetchPolicy.toJs), + fetchPolicy: t.fetchPolicy->Belt.Option.map(WatchQueryFetchPolicy.toJs), notifyOnNetworkStatusChange: t.notifyOnNetworkStatusChange, query: t.query, pollInterval: t.pollInterval, @@ -104,13 +107,13 @@ module QueryResult = { type t('jsData, 'variables) = { fetchMore: t_fetchMoreOptions('jsData, 'variables) => - Js.Promise.t(Core.Types.ApolloQueryResult.t('jsData)), + Js.Promise.t(ApolloQueryResult.t('jsData)), called: bool, client: ApolloClient__ApolloClient.t, data: option('jsData), - error: option(Errors.ApolloError.t), + error: option(ApolloError.t), loading: bool, - networkStatus: Core.NetworkStatus.t, + networkStatus: NetworkStatus.t, }; }; @@ -118,7 +121,7 @@ module QueryResult = { called: bool, client: ApolloClient__ApolloClient.t, data: option('parsedData), - error: option(Errors.ApolloError.t), + error: option(ApolloError.t), fetchMore: ( ~context: Js.Json.t=?, @@ -133,9 +136,9 @@ module QueryResult = { 'parsedData, unit ) => - Js.Promise.t(Core.Types.ApolloQueryResult.t('parsedData)), + Js.Promise.t(ApolloQueryResult.t('parsedData)), loading: bool, - networkStatus: Core.NetworkStatus.t, + networkStatus: NetworkStatus.t, }; let fromJs: @@ -168,9 +171,7 @@ module QueryResult = { }) ->Js.Promise.then_( jsResult => - Js.Promise.resolve( - Core.Types.ApolloQueryResult.fromJs(jsResult, ~parse), - ), + Js.Promise.resolve(ApolloQueryResult.fromJs(jsResult, ~parse)), _, ); }, From 7d8fe73cc75a06b62e60185a98c422dc5dd690bb Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Wed, 3 Jun 2020 18:37:21 -0500 Subject: [PATCH 10/21] refactor: make variables required --- src/ApolloClient__Types.re | 5 +++++ .../hooks/ApolloClient__React_UseQuery.re | 19 +++++++++++------ .../ApolloClient__React_UseSubscription.re | 21 ++++++++++++------- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/ApolloClient__Types.re b/src/ApolloClient__Types.re index 2db60fe..fff2c58 100644 --- a/src/ApolloClient__Types.re +++ b/src/ApolloClient__Types.re @@ -8,6 +8,11 @@ type graphqlDefinition('t, 'raw_t) = ( serialize('t, 'raw_t), ); +type variablesArg('variables) = + // Js.Json.t is the type of Raw.t_variables in graphql-ppx when there are no variables + | NoVariables: variablesArg(Js.Json.t) + | Variables('variables): variablesArg('variables); + module type Operation = { let query: string; diff --git a/src/react/hooks/ApolloClient__React_UseQuery.re b/src/react/hooks/ApolloClient__React_UseQuery.re index ee409a7..58d8879 100644 --- a/src/react/hooks/ApolloClient__React_UseQuery.re +++ b/src/react/hooks/ApolloClient__React_UseQuery.re @@ -4,6 +4,7 @@ module Graphql = ApolloClient__Graphql; module GraphqlTag = ApolloClient__GraphqlTag; module QueryHookOptions = ApolloClient__React_Types.QueryHookOptions; module QueryResult = ApolloClient__React_Types.QueryResult; +module Types = ApolloClient__Types; module WatchQueryFetchPolicy = ApolloClient__Core_WatchQueryOptions.WatchQueryFetchPolicy; module type Operation = ApolloClient__Types.Operation; @@ -27,7 +28,7 @@ module Js_ = { }; let useQuery: - type data variables jsData jsVariables. + type data jsData jsVariables. ( ~client: ApolloClient__ApolloClient.t=?, ~context: Js.Json.t=?, @@ -41,13 +42,13 @@ let useQuery: ~pollInterval: int=?, ~skip: bool=?, ~ssr: bool=?, - ~variables: variables=?, + ~variables: Types.variablesArg(jsVariables), (module Operation with type t = data and type Raw.t = jsData and type Raw.t_variables = jsVariables) ) => - QueryResult.t(data, variables) = + QueryResult.t(data, jsVariables) = ( ~client=?, ~context=?, @@ -61,9 +62,15 @@ let useQuery: ~pollInterval=?, ~skip=?, ~ssr=?, - ~variables=?, + ~variables as variablesArg, (module Definition), ) => { + let variables = + switch (variablesArg) { + | Types.NoVariables => None + | Types.Variables(v) => Some(v) + }; + let jsQueryResult = Js_.useQuery( ~query=GraphqlTag.gql(Definition.query), @@ -115,7 +122,7 @@ module Extend = (M: Operation) => { ~pollInterval=?, ~skip=?, ~ssr=?, - ~variables=?, + ~variables, (), ) => { useQuery( @@ -131,7 +138,7 @@ module Extend = (M: Operation) => { ~pollInterval?, ~skip?, ~ssr?, - ~variables?, + ~variables, (module M), ); }; diff --git a/src/react/hooks/ApolloClient__React_UseSubscription.re b/src/react/hooks/ApolloClient__React_UseSubscription.re index 1557099..6caff6b 100644 --- a/src/react/hooks/ApolloClient__React_UseSubscription.re +++ b/src/react/hooks/ApolloClient__React_UseSubscription.re @@ -5,6 +5,7 @@ module Graphql = ApolloClient__Graphql; module GraphqlTag = ApolloClient__GraphqlTag; module OnSubscriptionDataOptions = ApolloClient__React_Types.OnSubscriptionDataOptions; module SubscriptionHookOptions = ApolloClient__React_Types.SubscriptionHookOptions; +module Types = ApolloClient__Types; module type Operation = ApolloClient__Types.Operation; @@ -40,21 +41,22 @@ type useSubscription_result('data, 'variables) = { }; let useSubscription: - type data variables jsData jsVariables. + type data jsData jsVariables. ( ~client: ApolloClient__ApolloClient.t=?, ~fetchPolicy: FetchPolicy.t=?, ~onSubscriptionData: OnSubscriptionDataOptions.t(data) => unit=?, ~onSubscriptionComplete: unit => unit=?, - ~shouldResubscribe: BaseSubscriptionOptions.t(data, variables) => bool=?, + ~shouldResubscribe: BaseSubscriptionOptions.t(data, jsVariables) => bool + =?, ~skip: bool=?, - ~variables: variables=?, + ~variables: Types.variablesArg(jsVariables), (module Operation with type t = data and type Raw.t = jsData and type Raw.t_variables = jsVariables) ) => - useSubscription_result(data, variables) = + useSubscription_result(data, jsVariables) = ( ~client=?, ~fetchPolicy=?, @@ -62,9 +64,14 @@ let useSubscription: ~onSubscriptionComplete=?, ~shouldResubscribe=?, ~skip=?, - ~variables=?, + ~variables as variablesArg, (module Definition), ) => { + let variables = + switch (variablesArg) { + | Types.NoVariables => None + | Types.Variables(v) => Some(v) + }; let jsSubscriptionResult = Js_.useSubscription( ~subscription=GraphqlTag.gql(Definition.query), @@ -105,7 +112,7 @@ module Extend = (M: Operation) => { ~onSubscriptionComplete=?, ~shouldResubscribe=?, ~skip=?, - ~variables=?, + ~variables, (), ) => { useSubscription( @@ -115,7 +122,7 @@ module Extend = (M: Operation) => { ~onSubscriptionComplete?, ~shouldResubscribe?, ~skip?, - ~variables?, + ~variables, (module M), ); }; From 2becb05292c78b05b6ce69840857b976db586994 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Thu, 4 Jun 2020 21:10:35 -0500 Subject: [PATCH 11/21] refactor: add apollo link --- src/ApolloClient__ApolloClient.re | 54 ++++++++++++- .../ApolloClient__ZenObservable.re | 77 +++++++++++++++++++ .../ApolloClient__Link_Core_ApolloLink.re | 46 +++++++++++ .../core/ApolloClient__Link_Core_Types.re | 44 +++++++++++ .../ApolloClient_SelectHttpOptionsAndBody.re | 50 ++++++++++++ 5 files changed, 268 insertions(+), 3 deletions(-) create mode 100644 src/_dependencies/zen-observable/ApolloClient__ZenObservable.re create mode 100644 src/link/core/ApolloClient__Link_Core_ApolloLink.re create mode 100644 src/link/http/ApolloClient_SelectHttpOptionsAndBody.re diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re index 3df2f3e..4c1e010 100644 --- a/src/ApolloClient__ApolloClient.re +++ b/src/ApolloClient__ApolloClient.re @@ -1,4 +1,5 @@ module ApolloQueryResult = ApolloClient__Core_Types.ApolloQueryResult; +module ApolloLink = ApolloClient__Link_Core_ApolloLink; module DataProxy = ApolloClient__Cache_Core_Types.DataProxy; module ErrorPolicy = ApolloClient__Core_WatchQueryOptions.ErrorPolicy; module FetchPolicy = ApolloClient__Core_WatchQueryOptions.FetchPolicy; @@ -12,6 +13,7 @@ module MutationUpdaterFn = ApolloClient__Core_WatchQueryOptions.MutationUpdaterF module QueryOptions = ApolloClient__Core_WatchQueryOptions.QueryOptions; module PureQueryOptions = ApolloClient__Core_Types.PureQueryOptions; module RefetchQueryDescription = ApolloClient__Core_WatchQueryOptions.RefetchQueryDescription; +module UriFunction = ApolloClient_SelectHttpOptionsAndBody.UriFunction; module Types = ApolloClient__Types; // /// @@ -54,7 +56,6 @@ module Types = ApolloClient__Types; // private resetStoreCallbacks; // private clearStoreCallbacks; // private localState; -// constructor(options: ApolloClientOptions); // stop(): void; // watchQuery(options: WatchQueryOptions): ObservableQuery; // subscribe(options: SubscriptionOptions): Observable>; @@ -74,14 +75,54 @@ module Types = ApolloClient__Types; // getResolvers(): Resolvers; // setLocalStateFragmentMatcher(fragmentMatcher: FragmentMatcher): void; // } - -type t; +module ApolloClientOptions = { + module Js_ = { + // export declare type ApolloClientOptions = { + // uri?: string | UriFunction; + // credentials?: string; + // headers?: Record; + // link?: ApolloLink; + // cache: ApolloCache; + // ssrForceFetchDelay?: number; + // ssrMode?: boolean; + // connectToDevTools?: boolean; + // queryDeduplication?: boolean; + // defaultOptions?: DefaultOptions; + // assumeImmutableResults?: boolean; + // resolvers?: Resolvers | Resolvers[]; + // typeDefs?: string | string[] | DocumentNode | DocumentNode[]; + // fragmentMatcher?: FragmentMatcher; + // name?: string; + // version?: string; + // }; + type t = { + uri: option(UriFunction.t), + credentials: option(string), + headers: Js.Dict.t(string), + link: option(ApolloLink.t), + // cache: ApolloCache.t('tCacheShape), + ssrForceFetchDelay: option(int), + ssrMode: option(bool), + connectToDevTools: option(bool), + queryDeduplication: option(bool), + // defaultOptions: option(DefaultOptions.t), + assumeImmutableResults: option(bool), + // resolvers: array(Resolvers.t), + typeDefs: array(GraphQL.documentNode), + // fragmentMatcher: option(FragmentMatcher.t), + name: option(string), + version: option(string), + }; + }; + type t = Js_.t; +}; type refetchQueryDescription = | PureQueryOptions(PureQueryOptions.t('variables)): refetchQueryDescription | String(string): refetchQueryDescription; module Js_ = { + type t; // mutate(options: MutationOptions): Promise>; [@bs.send] external mutate: @@ -113,8 +154,15 @@ module Js_ = { (t, ~options: DataProxy.WriteQueryOptions.Js_.t('jsData, 'variables)) => unit = "writeQuery"; + + [@bs.module "@apollo/client"] [@bs.new] + external make: ApolloClientOptions.Js_.t => t = "ApolloClient"; }; +type t = Js_.t; + +let make: ApolloClientOptions.t => t = Js_.make; + let mutate: type data variables jsData jsVariables. ( diff --git a/src/_dependencies/zen-observable/ApolloClient__ZenObservable.re b/src/_dependencies/zen-observable/ApolloClient__ZenObservable.re new file mode 100644 index 0000000..329f1eb --- /dev/null +++ b/src/_dependencies/zen-observable/ApolloClient__ZenObservable.re @@ -0,0 +1,77 @@ +module ZenObservable = { + // interface SubscriptionObserver { + // closed: boolean; + // next(value: T): void; + // error(errorValue: any): void; + // complete(): void; + // } + + // type Subscriber = (observer: SubscriptionObserver) => void | (() => void) | Subscription; + + // interface ObservableLike { + // subscribe?: Subscriber; + // [Symbol.observable](): Observable | ObservableLike; + // } + + // interface Subscription { + // closed: boolean; + // unsubscribe(): void; + // } + type subscription = { + closed: bool, + unsubscribe: unit => unit, + }; + + // interface Observer { + // start?(subscription: Subscription): any; + // next?(value: T): void; + // error?(errorValue: any): void; + // complete?(): void; + // } + type observer('t) = { + start: option(subscription => unit), + next: option('t => unit), + error: option(Js.Json.t => unit), + complete: option(unit => unit), + }; +}; + +module Observable = { + // declare class Observable { + // constructor(subscriber: ZenObservable.Subscriber) + + // subscribe(observer: ZenObservable.Observer): ZenObservable.Subscription; + // subscribe(onNext: (value: T) => void, onError?: (error: any) => void, onComplete?: () => void): ZenObservable.Subscription; + + // [Symbol.observable](): Observable; + + // forEach(callback: (value: T) => void): Promise; + // map(callback: (value: T) => R): Observable; + // filter(callback: (value: T) => boolean): Observable; + // reduce(callback: (previousValue: T, currentValue: T) => T, initialValue?: T): Observable; + // reduce(callback: (previousValue: R, currentValue: T) => R, initialValue?: R): Observable; + // flatMap(callback: (value: T) => ZenObservable.ObservableLike): Observable; + // concat(...observable: Array>): Observable; + + // static from(observable: Observable | ZenObservable.ObservableLike | ArrayLike): Observable; + // static of(...items: R[]): Observable; + // } + type t('t); + + [@bs.send] + external subscribe: + ( + t('t), + ~onNext: 't => unit, + ~onError: Js.Json.t => unit=?, + ~onComplete: unit => unit=?, + unit + ) => + ZenObservable.subscription = + "subscribe"; + + [@bs.send] + external subscribeWithObserver: + (t('t), ZenObservable.observer('t)) => ZenObservable.subscription = + "subscribe"; +}; diff --git a/src/link/core/ApolloClient__Link_Core_ApolloLink.re b/src/link/core/ApolloClient__Link_Core_ApolloLink.re new file mode 100644 index 0000000..161434f --- /dev/null +++ b/src/link/core/ApolloClient__Link_Core_ApolloLink.re @@ -0,0 +1,46 @@ +module Operation = ApolloClient__Link_Core_Types.Operation; +module RequestHandler = ApolloClient__Link_Core_Types.RequestHandler; +// import { Observable } from '../../utilities/observables/Observable'; +// import { NextLink, Operation, RequestHandler, FetchResult, GraphQLRequest } from './types'; + +module Js_ = { + // export declare class ApolloLink { + // static empty(): ApolloLink; + // static from(links: (ApolloLink | RequestHandler)[]): ApolloLink; + // static split(test: (op: Operation) => boolean, left: ApolloLink | RequestHandler, right?: ApolloLink | RequestHandler): ApolloLink; + // static execute(link: ApolloLink, operation: GraphQLRequest): Observable; + // static concat(first: ApolloLink | RequestHandler, second: ApolloLink | RequestHandler): ApolloLink; + // constructor(request?: RequestHandler); + // split(test: (op: Operation) => boolean, left: ApolloLink | RequestHandler, right?: ApolloLink | RequestHandler): ApolloLink; + // concat(next: ApolloLink | RequestHandler): ApolloLink; + // request(operation: Operation, forward?: NextLink): Observable | null; + // protected onError(reason: any): void; + // setOnError(fn: (reason: any) => any): this; + // } + type t; + + [@bs.module "@apollo/client"] [@bs.new] + external make: RequestHandler.Js_.t => t = "ApolloClient"; + + [@bs.send] external concat: (t, t) => t = "concat"; + + [@bs.send] external from: (t, array(t)) => t = "from"; + + [@bs.send] external setOnError: (t, Js.Json.t => unit) => unit = "onError"; + + [@bs.send] + external split: (t, ~test: Operation.Js_.t => bool, ~left: t, ~right: t) => t = + "split"; +}; + +type t = Js_.t; + +let make: RequestHandler.t => t = Js_.make; + +let concat = Js_.concat; + +let from = Js_.from; + +let setOnError = Js_.setOnError; + +let split = Js_.split; diff --git a/src/link/core/ApolloClient__Link_Core_Types.re b/src/link/core/ApolloClient__Link_Core_Types.re index 3447518..51c1bf0 100644 --- a/src/link/core/ApolloClient__Link_Core_Types.re +++ b/src/link/core/ApolloClient__Link_Core_Types.re @@ -1,4 +1,29 @@ +module Graphql = ApolloClient__Graphql; module GraphQLError = ApolloClient__Graphql_Error_GraphQLError; +module Observable = ApolloClient__ZenObservable.Observable; + +module Operation = { + module Js_ = { + // export interface Operation { + // query: DocumentNode; + // variables: Record; + // operationName: string; + // extensions: Record; + // setContext: (context: Record) => Record; + // getContext: () => Record; + // } + type t = { + query: Graphql.documentNode, + variables: Js.Json.t, + operationName: string, + extensions: Js.Json.t, + setContext: Js.Json.t => Js.Json.t, + getContext: unit => Js.Json.t, + }; + }; + + type t = Js_.t; +}; module FetchResult = { module Js_ = { @@ -10,6 +35,7 @@ module FetchResult = { // context?: C; // } type t('jsData) = { + // TODO: option(Js.nullable('jsData)) data: option('jsData), extensions: option(Js.Json.t), // ACTUAL: Record context: option(Js.Json.t), // ACTUAL: Record @@ -38,3 +64,21 @@ module FetchResult = { }; }; }; + +module NextLink = { + module Js_ = { + // export declare type NextLink = (operation: Operation) => Observable; + type t = Operation.Js_.t => Observable.t(FetchResult.Js_.t(Js.Json.t)); + }; +}; + +module RequestHandler = { + module Js_ = { + // export declare type RequestHandler = (operation: Operation, forward: NextLink) => Observable | null; + type t = + (Operation.Js_.t, NextLink.Js_.t) => + Js.nullable(Observable.t(FetchResult.Js_.t(Js.Json.t))); + }; + + type t = Js_.t; +}; diff --git a/src/link/http/ApolloClient_SelectHttpOptionsAndBody.re b/src/link/http/ApolloClient_SelectHttpOptionsAndBody.re new file mode 100644 index 0000000..8c83923 --- /dev/null +++ b/src/link/http/ApolloClient_SelectHttpOptionsAndBody.re @@ -0,0 +1,50 @@ +module Operation = ApolloClient__Link_Core_Types.Operation; + +// import { Operation } from '../core/types'; +// export interface Body { +// query?: string; +// operationName?: string; +// variables?: Record; +// extensions?: Record; +// } +// export interface HttpOptions { +// uri?: string | UriFunction; +// includeExtensions?: boolean; +// fetch?: WindowOrWorkerGlobalScope['fetch']; +// headers?: any; +// credentials?: string; +// fetchOptions?: any; +// useGETForQueries?: boolean; +// } +// export interface HttpQueryOptions { +// includeQuery?: boolean; +// includeExtensions?: boolean; +// } +// export interface HttpConfig { +// http?: HttpQueryOptions; +// options?: any; +// headers?: any; +// credentials?: any; +// } +// export declare const fallbackHttpConfig: { +// http: HttpQueryOptions; +// headers: { +// accept: string; +// 'content-type': string; +// }; +// options: { +// method: string; +// }; +// }; +// export declare const selectHttpOptionsAndBody: (operation: Operation, fallbackConfig: HttpConfig, ...configs: Array) => { +// options: HttpConfig & Record; +// body: Body; +// }; + +module UriFunction = { + module Js_ = { + type t = Operation.Js_.t => string; + }; + + type t = Js_.t; +}; From 872bd30778f9e095dfa5998d775e188b5038ea53 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Fri, 5 Jun 2020 16:09:27 -0500 Subject: [PATCH 12/21] refactor: add defaultOptions --- src/ApolloClient__ApolloClient.re | 282 ++++++++++++++---- src/ApolloClient__Types.re | 5 + .../core/ApolloClient__Cache_Core_Cache.re | 37 ++- .../ApolloClient__Core_WatchQueryOptions.re | 38 ++- 4 files changed, 295 insertions(+), 67 deletions(-) diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re index 4c1e010..3d0ea80 100644 --- a/src/ApolloClient__ApolloClient.re +++ b/src/ApolloClient__ApolloClient.re @@ -1,5 +1,6 @@ module ApolloQueryResult = ApolloClient__Core_Types.ApolloQueryResult; module ApolloLink = ApolloClient__Link_Core_ApolloLink; +module ApolloCache = ApolloClient__Cache_Core_Cache.ApolloCache; module DataProxy = ApolloClient__Cache_Core_Types.DataProxy; module ErrorPolicy = ApolloClient__Core_WatchQueryOptions.ErrorPolicy; module FetchPolicy = ApolloClient__Core_WatchQueryOptions.FetchPolicy; @@ -15,66 +16,153 @@ module PureQueryOptions = ApolloClient__Core_Types.PureQueryOptions; module RefetchQueryDescription = ApolloClient__Core_WatchQueryOptions.RefetchQueryDescription; module UriFunction = ApolloClient_SelectHttpOptionsAndBody.UriFunction; module Types = ApolloClient__Types; +module WatchQueryFetchPolicy = ApolloClient__Core_WatchQueryOptions.WatchQueryFetchPolicy; +module WatchQueryOptions = ApolloClient__Core_WatchQueryOptions.QueryOptions; -// /// +module DefaultOptions = { + module DefaultWatchQueryOptions = { + module Js_ = { + // Partial; + type t = { + fetchPolicy: option(WatchQueryFetchPolicy.Js_.t), + // query: GraphQL.Language.documentNode, + // variables: option('variables), + errorPolicy: option(ErrorPolicy.Js_.t), + context: option(Js.Json.t), + }; + }; + + type t = { + fetchPolicy: option(WatchQueryFetchPolicy.t), + errorPolicy: option(ErrorPolicy.t), + context: option(Js.Json.t), + }; + + let toJs: t => Js_.t = + t => { + fetchPolicy: + t.fetchPolicy->Belt.Option.map(WatchQueryFetchPolicy.toJs), + errorPolicy: t.errorPolicy->Belt.Option.map(ErrorPolicy.toJs), + context: t.context, + }; + }; -// export interface DefaultOptions { -// watchQuery?: Partial; -// query?: Partial; -// mutate?: Partial; -// } + module DefaultQueryOptions = { + module Js_ = { + // Partial; + type t = { + fetchPolicy: option(FetchPolicy.Js_.t), + // query: GraphQL.Language.documentNode, + // variables: option('variables), + errorPolicy: option(ErrorPolicy.Js_.t), + context: option(Js.Json.t), + }; + }; -// export declare type ApolloClientOptions = { -// uri?: string | UriFunction; -// credentials?: string; -// headers?: Record; -// link?: ApolloLink; -// cache: ApolloCache; -// ssrForceFetchDelay?: number; -// ssrMode?: boolean; -// connectToDevTools?: boolean; -// queryDeduplication?: boolean; -// defaultOptions?: DefaultOptions; -// assumeImmutableResults?: boolean; -// resolvers?: Resolvers | Resolvers[]; -// typeDefs?: string | string[] | DocumentNode | DocumentNode[]; -// fragmentMatcher?: FragmentMatcher; -// name?: string; -// version?: string; -// }; + type t = { + fetchPolicy: option(FetchPolicy.t), + errorPolicy: option(ErrorPolicy.t), + context: option(Js.Json.t), + }; + + let toJs: t => Js_.t = + t => { + fetchPolicy: t.fetchPolicy->Belt.Option.map(FetchPolicy.toJs), + errorPolicy: t.errorPolicy->Belt.Option.map(ErrorPolicy.toJs), + context: t.context, + }; + }; + + module DefaultMutationOptions = { + module Js_ = { + // Partial; + type t = { + context: option(Js.Json.t), + fetchPolicy: option(FetchPolicy__noCacheExtracted.Js_.t), + awaitRefetchQueries: option(bool), + errorPolicy: option(ErrorPolicy.Js_.t), + // optimisticResponse: option('variables => 'jsData), + // update: option(MutationUpdaterFn.Js_.t('jsData)), + // updateQueries: option(MutationQueryReducersMap.Js_.t('jsData)), + refetchQueries: option(RefetchQueryDescription.Js_.t), + // variables: option('variables), + }; + }; + + type t = { + context: option(Js.Json.t), + fetchPolicy: option(FetchPolicy__noCacheExtracted.t), + awaitRefetchQueries: option(bool), + errorPolicy: option(ErrorPolicy.t), + refetchQueries: option(RefetchQueryDescription.t), + }; + + let toJs: t => Js_.t = + t => { + context: t.context, + fetchPolicy: + t.fetchPolicy->Belt.Option.map(FetchPolicy__noCacheExtracted.toJs), + awaitRefetchQueries: t.awaitRefetchQueries, + errorPolicy: t.errorPolicy->Belt.Option.map(ErrorPolicy.toJs), + refetchQueries: + t.refetchQueries->Belt.Option.map(RefetchQueryDescription.toJs), + }; + + let make = + ( + ~context=?, + ~fetchPolicy=?, + ~awaitRefetchQueries=?, + ~errorPolicy=?, + ~refetchQueries=?, + (), + ) => { + context, + fetchPolicy, + awaitRefetchQueries, + errorPolicy, + refetchQueries, + }; + }; + + module Js_ = { + // export interface DefaultOptions { + // watchQuery?: Partial; + // query?: Partial; + // mutate?: Partial; + // } + type t = { + watchQuery: option(DefaultWatchQueryOptions.Js_.t), + query: option(DefaultQueryOptions.Js_.t), + mutate: option(DefaultMutationOptions.Js_.t), + }; + }; + + type t = { + watchQuery: option(DefaultWatchQueryOptions.t), + query: option(DefaultQueryOptions.t), + mutate: option(DefaultMutationOptions.t), + }; + + let toJs: t => Js_.t = + t => { + watchQuery: + t.watchQuery->Belt.Option.map(DefaultWatchQueryOptions.toJs), + query: t.query->Belt.Option.map(DefaultQueryOptions.toJs), + mutate: t.mutate->Belt.Option.map(DefaultMutationOptions.toJs), + }; + + let make: + ( + ~mutate: DefaultMutationOptions.t=?, + ~query: DefaultQueryOptions.t=?, + ~watchQuery: DefaultWatchQueryOptions.t=?, + unit + ) => + t = + (~mutate=?, ~query=?, ~watchQuery=?, ()) => {watchQuery, query, mutate}; +}; -// export declare class ApolloClient implements DataProxy { -// link: ApolloLink; -// cache: ApolloCache; -// disableNetworkFetches: boolean; -// version: string; -// queryDeduplication: boolean; -// defaultOptions: DefaultOptions; -// readonly typeDefs: ApolloClientOptions['typeDefs']; -// private queryManager; -// private devToolsHookCb; -// private resetStoreCallbacks; -// private clearStoreCallbacks; -// private localState; -// stop(): void; -// watchQuery(options: WatchQueryOptions): ObservableQuery; -// subscribe(options: SubscriptionOptions): Observable>; -// readFragment(options: DataProxy.Fragment, optimistic?: boolean): T | null; -// writeFragment(options: DataProxy.WriteFragmentOptions): void; -// __actionHookForDevTools(cb: () => any): void; -// __requestRaw(payload: GraphQLRequest): Observable; -// resetStore(): Promise[] | null>; -// clearStore(): Promise; -// onResetStore(cb: () => Promise): () => void; -// onClearStore(cb: () => Promise): () => void; -// reFetchObservableQueries(includeStandby?: boolean): Promise[]>; -// extract(optimistic?: boolean): TCacheShape; -// restore(serializedState: TCacheShape): ApolloCache; -// addResolvers(resolvers: Resolvers | Resolvers[]): void; -// setResolvers(resolvers: Resolvers | Resolvers[]): void; -// getResolvers(): Resolvers; -// setLocalStateFragmentMatcher(fragmentMatcher: FragmentMatcher): void; -// } module ApolloClientOptions = { module Js_ = { // export declare type ApolloClientOptions = { @@ -96,16 +184,16 @@ module ApolloClientOptions = { // version?: string; // }; type t = { - uri: option(UriFunction.t), + uri: option(UriFunction.Js_.t), credentials: option(string), headers: Js.Dict.t(string), - link: option(ApolloLink.t), - // cache: ApolloCache.t('tCacheShape), + link: option(ApolloLink.Js_.t), + cache: ApolloCache.Js_.t(Js.Json.t), ssrForceFetchDelay: option(int), ssrMode: option(bool), connectToDevTools: option(bool), queryDeduplication: option(bool), - // defaultOptions: option(DefaultOptions.t), + defaultOptions: option(DefaultOptions.Js_.t), assumeImmutableResults: option(bool), // resolvers: array(Resolvers.t), typeDefs: array(GraphQL.documentNode), @@ -114,7 +202,43 @@ module ApolloClientOptions = { version: option(string), }; }; - type t = Js_.t; + + type t = { + uri: option(UriFunction.t), + credentials: option(string), + headers: Js.Dict.t(string), + link: option(ApolloLink.t), + cache: ApolloCache.Js_.t(Js.Json.t), + ssrForceFetchDelay: option(int), + ssrMode: option(bool), + connectToDevTools: option(bool), + queryDeduplication: option(bool), + defaultOptions: option(DefaultOptions.t), + assumeImmutableResults: option(bool), + // resolvers: array(Resolvers.t), + typeDefs: array(GraphQL.documentNode), + // fragmentMatcher: option(FragmentMatcher.t), + name: option(string), + version: option(string), + }; + + let toJs: t => Js_.t = + t => { + uri: t.uri, + credentials: t.credentials, + headers: t.headers, + link: t.link, + cache: t.cache, + ssrForceFetchDelay: t.ssrForceFetchDelay, + ssrMode: t.ssrMode, + connectToDevTools: t.connectToDevTools, + queryDeduplication: t.queryDeduplication, + defaultOptions: t.defaultOptions->Belt.Option.map(DefaultOptions.toJs), + assumeImmutableResults: t.assumeImmutableResults, + typeDefs: t.typeDefs, + name: t.name, + version: t.version, + }; }; type refetchQueryDescription = @@ -122,6 +246,38 @@ type refetchQueryDescription = | String(string): refetchQueryDescription; module Js_ = { + // export declare class ApolloClient implements DataProxy { + // link: ApolloLink; + // cache: ApolloCache; + // disableNetworkFetches: boolean; + // version: string; + // queryDeduplication: boolean; + // defaultOptions: DefaultOptions; + // readonly typeDefs: ApolloClientOptions['typeDefs']; + // private queryManager; + // private devToolsHookCb; + // private resetStoreCallbacks; + // private clearStoreCallbacks; + // private localState; + // stop(): void; + // watchQuery(options: WatchQueryOptions): ObservableQuery; + // subscribe(options: SubscriptionOptions): Observable>; + // readFragment(options: DataProxy.Fragment, optimistic?: boolean): T | null; + // writeFragment(options: DataProxy.WriteFragmentOptions): void; + // __actionHookForDevTools(cb: () => any): void; + // __requestRaw(payload: GraphQLRequest): Observable; + // resetStore(): Promise[] | null>; + // clearStore(): Promise; + // onResetStore(cb: () => Promise): () => void; + // onClearStore(cb: () => Promise): () => void; + // reFetchObservableQueries(includeStandby?: boolean): Promise[]>; + // extract(optimistic?: boolean): TCacheShape; + // restore(serializedState: TCacheShape): ApolloCache; + // addResolvers(resolvers: Resolvers | Resolvers[]): void; + // setResolvers(resolvers: Resolvers | Resolvers[]): void; + // getResolvers(): Resolvers; + // setLocalStateFragmentMatcher(fragmentMatcher: FragmentMatcher): void; + // } type t; // mutate(options: MutationOptions): Promise>; [@bs.send] @@ -161,7 +317,9 @@ module Js_ = { type t = Js_.t; -let make: ApolloClientOptions.t => t = Js_.make; +let make: ApolloClientOptions.t => t = + apolloClientOptions => + Js_.make(apolloClientOptions->ApolloClientOptions.toJs); let mutate: type data variables jsData jsVariables. diff --git a/src/ApolloClient__Types.re b/src/ApolloClient__Types.re index fff2c58..caea1ec 100644 --- a/src/ApolloClient__Types.re +++ b/src/ApolloClient__Types.re @@ -25,3 +25,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; +}; diff --git a/src/cache/core/ApolloClient__Cache_Core_Cache.re b/src/cache/core/ApolloClient__Cache_Core_Cache.re index 1896441..fd403ab 100644 --- a/src/cache/core/ApolloClient__Cache_Core_Cache.re +++ b/src/cache/core/ApolloClient__Cache_Core_Cache.re @@ -1 +1,36 @@ -type t; +// import { DocumentNode } from 'graphql'; +// import { StoreObject } from '../../utilities/graphql/storeUtils'; +// import { DataProxy } from './types/DataProxy'; +// import { Cache } from './types/Cache'; +// export declare type Transaction = (c: ApolloCache) => void; + +module ApolloCache = { + module Js_ = { + // export declare abstract class ApolloCache implements DataProxy { + // abstract read(query: Cache.ReadOptions): T | null; + // abstract write(write: Cache.WriteOptions): void; + // abstract diff(query: Cache.DiffOptions): Cache.DiffResult; + // abstract watch(watch: Cache.WatchOptions): () => void; + // abstract reset(): Promise; + // abstract evict(options: Cache.EvictOptions): boolean; + // abstract evict(id: string, field?: string, args?: Record): boolean; + // abstract restore(serializedState: TSerialized): ApolloCache; + // abstract extract(optimistic?: boolean): TSerialized; + // abstract removeOptimistic(id: string): void; + // abstract performTransaction(transaction: Transaction): void; + // abstract recordOptimisticTransaction(transaction: Transaction, id: string): void; + // transformDocument(document: DocumentNode): DocumentNode; + // identify(object: StoreObject): string | undefined; + // gc(): string[]; + // transformForLink(document: DocumentNode): DocumentNode; + // readQuery(options: DataProxy.Query, optimistic?: boolean): QueryType | null; + // private getFragmentDoc; + // readFragment(options: DataProxy.Fragment, optimistic?: boolean): FragmentType | null; + // writeQuery(options: Cache.WriteQueryOptions): void; + // writeFragment(options: Cache.WriteFragmentOptions): void; + // } + type t('tSerialized); + }; + + type t('tSerialized) = Js_.t('tSerialized); +}; diff --git a/src/core/ApolloClient__Core_WatchQueryOptions.re b/src/core/ApolloClient__Core_WatchQueryOptions.re index 11cbcb1..0035ce9 100644 --- a/src/core/ApolloClient__Core_WatchQueryOptions.re +++ b/src/core/ApolloClient__Core_WatchQueryOptions.re @@ -1,4 +1,4 @@ -module Cache = ApolloClient__Cache_Core_Cache; +module ApolloCache = ApolloClient__Cache_Core_Cache.ApolloCache; module FetchResult = ApolloClient__Link_Core_Types.FetchResult; module GraphQL = ApolloClient__Graphql; module GraphqlTag = ApolloClient__Graphql; @@ -103,7 +103,6 @@ module QueryOptions = { type t('variables) = { fetchPolicy: option(FetchPolicy.t), - // ...extends QueryBaseOptions query: ApolloClient__Graphql.documentNode, variables: option('variables), errorPolicy: option(ErrorPolicy.t), @@ -120,12 +119,43 @@ module QueryOptions = { }; }; +module WatchQueryOptions = { + module Js_ = { + type t('variables) = { + fetchPolicy: option(WatchQueryFetchPolicy.Js_.t), + // ...extends QueryBaseOptions + query: GraphQL.Language.documentNode, + variables: option('variables), + errorPolicy: option(ErrorPolicy.Js_.t), + context: option(Js.Json.t), + }; + }; + + type t('variables) = { + fetchPolicy: option(WatchQueryFetchPolicy.t), + query: ApolloClient__Graphql.documentNode, + variables: option('variables), + errorPolicy: option(ErrorPolicy.t), + context: option(Js.Json.t), + }; + + let toJs: t('variables) => Js_.t('variables) = + t => { + fetchPolicy: t.fetchPolicy->Belt.Option.map(WatchQueryFetchPolicy.toJs), + query: t.query, + variables: t.variables, + errorPolicy: t.errorPolicy->Belt.Option.map(ErrorPolicy.toJs), + context: t.context, + }; +}; + module MutationUpdaterFn = { module Js_ = { - type t('jsData) = (. Cache.t, FetchResult.Js_.t('jsData)) => unit; + type t('jsData) = + (. ApolloCache.Js_.t(Js.Json.t), FetchResult.Js_.t('jsData)) => unit; }; - type t('data) = (Cache.t, FetchResult.t('data)) => unit; + type t('data) = (ApolloCache.t(Js.Json.t), FetchResult.t('data)) => unit; let toJs: (t('data), ~parse: Types.parse('jsData, 'data)) => Js_.t('jsData) = From f03c39f8403356c5eb51a35568580173b1762578 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Fri, 5 Jun 2020 17:41:21 -0500 Subject: [PATCH 13/21] refactor: finish ApolloClient construction --- src/ApolloClient__ApolloClient.re | 12 +- .../ApolloClient__Graphql_Language_Ast.re | 140 ++++++++++++++++++ .../ApolloClient__Graphql_Language_Source.re | 11 ++ src/core/ApolloClient__Core_LocalState.re | 36 +++++ src/core/ApolloClient__Core_Types.re | 13 ++ ...olloClient__Utilities_Graphql_Fragments.re | 9 ++ 6 files changed, 217 insertions(+), 4 deletions(-) create mode 100644 src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Ast.re create mode 100644 src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Source.re create mode 100644 src/core/ApolloClient__Core_LocalState.re create mode 100644 src/utilities/ApolloClient__Utilities_Graphql_Fragments.re diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re index 3d0ea80..0014616 100644 --- a/src/ApolloClient__ApolloClient.re +++ b/src/ApolloClient__ApolloClient.re @@ -5,6 +5,7 @@ module DataProxy = ApolloClient__Cache_Core_Types.DataProxy; module ErrorPolicy = ApolloClient__Core_WatchQueryOptions.ErrorPolicy; module FetchPolicy = ApolloClient__Core_WatchQueryOptions.FetchPolicy; module FetchPolicy__noCacheExtracted = ApolloClient__Core_WatchQueryOptions.FetchPolicy__noCacheExtracted; +module FragmentMatcher = ApolloClient__Core_LocalState.FragmentMatcher; module GraphQL = ApolloClient__Graphql; module GraphqlTag = ApolloClient__GraphqlTag; module FetchResult = ApolloClient__Link_Core_Types.FetchResult; @@ -14,6 +15,7 @@ module MutationUpdaterFn = ApolloClient__Core_WatchQueryOptions.MutationUpdaterF module QueryOptions = ApolloClient__Core_WatchQueryOptions.QueryOptions; module PureQueryOptions = ApolloClient__Core_Types.PureQueryOptions; module RefetchQueryDescription = ApolloClient__Core_WatchQueryOptions.RefetchQueryDescription; +module Resolvers = ApolloClient__Core_Types.Resolvers; module UriFunction = ApolloClient_SelectHttpOptionsAndBody.UriFunction; module Types = ApolloClient__Types; module WatchQueryFetchPolicy = ApolloClient__Core_WatchQueryOptions.WatchQueryFetchPolicy; @@ -195,9 +197,9 @@ module ApolloClientOptions = { queryDeduplication: option(bool), defaultOptions: option(DefaultOptions.Js_.t), assumeImmutableResults: option(bool), - // resolvers: array(Resolvers.t), + resolvers: array(Resolvers.Js_.t), typeDefs: array(GraphQL.documentNode), - // fragmentMatcher: option(FragmentMatcher.t), + fragmentMatcher: option(FragmentMatcher.Js_.t), name: option(string), version: option(string), }; @@ -215,9 +217,9 @@ module ApolloClientOptions = { queryDeduplication: option(bool), defaultOptions: option(DefaultOptions.t), assumeImmutableResults: option(bool), - // resolvers: array(Resolvers.t), + resolvers: array(Resolvers.t), typeDefs: array(GraphQL.documentNode), - // fragmentMatcher: option(FragmentMatcher.t), + fragmentMatcher: option(FragmentMatcher.t), name: option(string), version: option(string), }; @@ -235,7 +237,9 @@ module ApolloClientOptions = { queryDeduplication: t.queryDeduplication, defaultOptions: t.defaultOptions->Belt.Option.map(DefaultOptions.toJs), assumeImmutableResults: t.assumeImmutableResults, + resolvers: t.resolvers, typeDefs: t.typeDefs, + fragmentMatcher: t.fragmentMatcher, name: t.name, version: t.version, }; diff --git a/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Ast.re b/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Ast.re new file mode 100644 index 0000000..95d803b --- /dev/null +++ b/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Ast.re @@ -0,0 +1,140 @@ +module Source = ApolloClient__Graphql_Language_Source; + +// export interface FieldNode { +// readonly kind: 'Field'; +// readonly loc?: Location; +// readonly alias?: NameNode; +// readonly name: NameNode; +// readonly arguments?: ReadonlyArray; +// readonly directives?: ReadonlyArray; +// readonly selectionSet?: SelectionSetNode; +// } + +module TokenKindEnum = { + [@bs.deriving jsConverter] + type t = [ + | `SOF + | `EOF + | `BANG + | `DOLLAR + | `AMP + | `PAREN_L + | `PAREN_R + | `SPREAD + | `COLON + | `EQUALS + | `AT + | `BRACKET_L + | `BRACKET_R + | `BRACE_L + | `PIPE + | `BRACE_R + | `NAME + | `INT + | `FLOAT + | `STRING + | `BLOCK_STRING + | `COMMENT + ]; +}; + +module Token = { + type t = { + kind: TokenKindEnum.t, + start: int, + [@bs.as "end"] + end_: int, + line: int, + column: int, + value: option(string), + prev: Js.nullable(t), + next: Js.nullable(t), + }; +}; + +module Location = { + type t = { + start: int, + [@bs.as "end"] + end_: int, + startToken: Token.t, + endToken: Token.t, + source: Source.t, + }; +}; + +module NameNode = { + type t = { + kind: string, + loc: option(Location.t), + value: string, + }; +}; + +module NamedTypeNode = { + type t = { + kind: string, + loc: option(Location.t), + name: NameNode.t, + }; +}; + +module ValueNode = { + type t; +}; + +module ArgumentNode = { + type t = { + kind: string, + loc: option(Location.t), + name: NameNode.t, + value: ValueNode.t, + }; +}; + +module DirectiveNode = { + type t = { + kind: string, + loc: option(Location.t), + name: NameNode.t, + arguments: option(array(ArgumentNode.t)), + }; +}; + +module SelectionNode = { + type t; +}; + +module SelectionSetNode = { + type t = { + kind: string, + loc: option(Location.t), + selections: array(SelectionNode.t), + }; +}; + +module FieldNode = { + type t = { + kind: string, + loc: option(Location.t), + alias: option(NameNode.t), + name: NameNode.t, + arguments: option(array(ArgumentNode.t)), + directives: option(array(DirectiveNode.t)), + selectionSet: option(SelectionSetNode.t), + }; +}; + +module FragmentDefinitionNode = { + type t = { + kind: string, + loc: option(Location.t), + name: NameNode.t, + // // Note: fragment variable definitions are experimental and may be changed + // // or removed in the future. + // readonly variableDefinitions?: ReadonlyArray; + typeCondition: NamedTypeNode.t, + directives: option(array(DirectiveNode.t)), + selectionSet: SelectionSetNode.t, + }; +}; diff --git a/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Source.re b/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Source.re new file mode 100644 index 0000000..5d09327 --- /dev/null +++ b/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Source.re @@ -0,0 +1,11 @@ +type location = { + line: int, + column: int, +}; + +type t = { + body: string, + name: string, + locationOffset: location, + // constructor(body: string, name?: string, locationOffset?: Location); +}; diff --git a/src/core/ApolloClient__Core_LocalState.re b/src/core/ApolloClient__Core_LocalState.re new file mode 100644 index 0000000..9cc5e43 --- /dev/null +++ b/src/core/ApolloClient__Core_LocalState.re @@ -0,0 +1,36 @@ +module FieldNode = ApolloClient__Graphql_Language_Ast.FieldNode; +module FragmentMap = ApolloClient__Utilities_Graphql_Fragments.FragmentMap; + +module FragmentMatcher = { + module Js_ = { + // export declare type FragmentMatcher = (rootValue: any, typeCondition: string, context: any) => boolean; + type t = (Js.Json.t, string, Js.Json.t) => bool; + }; + + type t = Js_.t; +}; + +// TODO: resolve dependency cycle +type apolloClient; + +module Resolver = { + module Js_ = { + type t_context = { + client: apolloClient, + cache: ApolloClient__Cache_Core_Cache.ApolloCache.t(Js.Json.t), + }; + + type t_info = { + field: FieldNode.t, + fragmentMap: FragmentMap.t, + }; + + // export declare type Resolver = (rootValue?: any, args?: any, context?: any, info?: { + // field: FieldNode; + // fragmentMap: FragmentMap; + // }) => any; + type t = (Js.Json.t, Js.Json.t, t_context, t_info) => Js.Json.t; + }; + + type t = Js_.t; +}; diff --git a/src/core/ApolloClient__Core_Types.re b/src/core/ApolloClient__Core_Types.re index 5e6b749..bcc7a4c 100644 --- a/src/core/ApolloClient__Core_Types.re +++ b/src/core/ApolloClient__Core_Types.re @@ -1,6 +1,7 @@ module Graphql = ApolloClient__Graphql; module GraphqlTag = ApolloClient__GraphqlTag; module FetchResult = ApolloClient__Link_Core_Types.FetchResult; +module Resolver = ApolloClient__Core_LocalState.Resolver; module Types = ApolloClient__Types; module PureQueryOptions = { @@ -122,3 +123,15 @@ module MutationQueryReducersMap = { ); }; }; + +module Resolvers = { + module Js_ = { + // export interface Resolvers { + // [key: string]: { + // [field: string]: Resolver; + // }; + // } + type t = Js.Dict.t(Js.Dict.t(Resolver.Js_.t)); + }; + type t = Js_.t; +}; diff --git a/src/utilities/ApolloClient__Utilities_Graphql_Fragments.re b/src/utilities/ApolloClient__Utilities_Graphql_Fragments.re new file mode 100644 index 0000000..36b36b6 --- /dev/null +++ b/src/utilities/ApolloClient__Utilities_Graphql_Fragments.re @@ -0,0 +1,9 @@ +module FragmentDefinitionNode = ApolloClient__Graphql_Language_Ast.FragmentDefinitionNode; + +module FragmentMap = { + module Js_ = { + type t = Js.Dict.t(FragmentDefinitionNode.t); + }; + + type t = Js_.t; +}; From 1a43e5a302ff0362d9c3306f63d167192ceb7f86 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sat, 6 Jun 2020 13:33:21 -0500 Subject: [PATCH 14/21] refactor: add HttpLink, WebSocketLink, InMemoryCache --- src/ApolloClient.re | 30 +++- src/ApolloClient__ApolloClient.re | 2 +- .../@apollo/link-ws/ApolloLinkWs.re | 69 +++++++ .../SubscriptionsTransportWs.re | 170 ++++++++++++++++++ .../ApolloClient__Graphql_Language.re | 2 + .../ApolloClient__Graphql_Language_Ast.re | 37 ++++ ...lloClient__Cache_InMemory_InMemoryCache.re | 66 +++++++ .../ApolloClient__Cache_InMemory_Policies.re | 71 ++++++++ .../ApolloClient__Link_Core_ApolloLink.re | 30 +++- .../core/ApolloClient__Link_Core_Types.re | 26 ++- .../ApolloClient_Link_Http_CreateHttpLink.re | 10 ++ .../http/ApolloClient_Link_Http_HttpLink.re | 14 ++ ...ent_Link_Http_SelectHttpOptionsAndBody.re} | 43 ++++- src/utilities/ApolloClient__Utilities.re | 1 + ...olloClient__Utilities_Graphql_Fragments.re | 0 ...lloClient__Utilities_Graphql_GetFromAst.re | 7 + 16 files changed, 556 insertions(+), 22 deletions(-) create mode 100644 src/_notDependencies/@apollo/link-ws/ApolloLinkWs.re create mode 100644 src/_notDependencies/subscriptions-transport-ws/SubscriptionsTransportWs.re create mode 100644 src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re create mode 100644 src/cache/inmemory/ApolloClient__Cache_InMemory_Policies.re create mode 100644 src/link/http/ApolloClient_Link_Http_CreateHttpLink.re create mode 100644 src/link/http/ApolloClient_Link_Http_HttpLink.re rename src/link/http/{ApolloClient_SelectHttpOptionsAndBody.re => ApolloClient_Link_Http_SelectHttpOptionsAndBody.re} (66%) create mode 100644 src/utilities/ApolloClient__Utilities.re rename src/utilities/{ => graphql}/ApolloClient__Utilities_Graphql_Fragments.re (100%) create mode 100644 src/utilities/graphql/ApolloClient__Utilities_Graphql_GetFromAst.re diff --git a/src/ApolloClient.re b/src/ApolloClient.re index 54adac2..1803d87 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -1,10 +1,12 @@ // export { default as Observable } from 'zen-observable'; +module Observable = ApolloClient__ZenObservable.Observable; // export { isReference, makeReference } from './utilities/graphql/storeUtils.js'; // export { ApolloLink } from './link/core/ApolloLink.js'; +module ApolloLink = ApolloClient__Link_Core_ApolloLink; // export { execute } from './link/core/execute.js'; +let execute = ApolloClient__Link_Core_ApolloLink.Static.execute; // export { ApolloError, isApolloError } from './errors/ApolloError.js'; // export { NetworkStatus } from './core/networkStatus.js'; -// export { FetchType } from './core/types.js'; // export { ObservableQuery } from './core/ObservableQuery.js'; // export { serializeFetchParameter } from './link/http/serializeFetchParameter.js'; // export { selectURI } from './link/http/selectURI.js'; @@ -15,35 +17,47 @@ // export { createSignalIfSupported } from './link/http/createSignalIfSupported.js'; // export { fromError } from './link/utils/fromError.js'; // export { createHttpLink } from './link/http/createHttpLink.js'; +let createHttpLink = ApolloClient_Link_Http_CreateHttpLink.createHttpLink; // export { HttpLink } from './link/http/HttpLink.js'; +module HttpLink = ApolloClient_Link_Http_HttpLink; +// export { ApolloClient } from './ApolloClient.js'; +module ApolloClient = ApolloClient__ApolloClient; // export { ApolloCache } from './cache/core/cache.js'; +module ApolloCache = ApolloClient__Cache_Core_Cache.ApolloCache; // export { Cache } from './cache/core/types/Cache.js'; // export { MissingFieldError } from './cache/core/types/common.js'; // export { defaultDataIdFromObject } from './cache/inmemory/policies.js'; +let defaultDataIdFromObject = ApolloClient__Cache_InMemory_Policies.defaultDataIdFromObject; // export { InMemoryCache } from './cache/inmemory/inMemoryCache.js'; +module InMemoryCache = ApolloClient__Cache_InMemory_InMemoryCache; // export { empty } from './link/core/empty.js'; +let empty = ApolloClient__Link_Core_ApolloLink.Static.empty; // export { from } from './link/core/from.js'; +let from = ApolloClient__Link_Core_ApolloLink.Static.from; // export { split } from './link/core/split.js'; +let split = ApolloClient__Link_Core_ApolloLink.Static.split; // export { concat } from './link/core/concat.js'; +let concat = ApolloClient__Link_Core_ApolloLink.Static.concat; // export { toPromise } from './link/utils/toPromise.js'; // export { fromPromise } from './link/utils/fromPromise.js'; +// export { default as gql } from 'graphql-tag'; +let gql = ApolloClient__GraphqlTag.gql; // export { disableExperimentalFragmentVariables, disableFragmentWarnings, enableExperimentalFragmentVariables, resetCaches } from './core/index.js'; // export { getApolloContext, resetApolloContext } from './react/context/ApolloContext.js'; // export { ApolloProvider } from './react/context/ApolloProvider.js'; +module ApolloProvider = ApolloClient__React_ApolloProvider; // export { ApolloConsumer } from './react/context/ApolloConsumer.js'; // export { DocumentType, operationName, parser } from './react/parser/parser.js'; +// export { useQuery } from './react/hooks/useQuery.js'; +let useQuery = ApolloClient__React_UseQuery.useQuery; // export { useLazyQuery } from './react/hooks/useLazyQuery.js'; // export { useMutation } from './react/hooks/useMutation.js'; +// export { useSubscription } from './react/hooks/useSubscription.js'; +let useSubscription = ApolloClient__React_UseSubscription.useSubscription; // export { useApolloClient } from './react/hooks/useApolloClient.js'; // export { RenderPromises } from './react/ssr/RenderPromises.js'; -module ApolloClient = ApolloClient__ApolloClient; -module ApolloProvider = ApolloClient__React_ApolloProvider; - module Extend = { - module Query = ApolloClient__React_UseQuery.Extend; + module UseQuery = ApolloClient__React_UseQuery.Extend; module Subscription = ApolloClient__React_UseSubscription.Extend; }; - -let useQuery = ApolloClient__React_UseQuery.useQuery; -let useSubscription = ApolloClient__React_UseSubscription.useSubscription; diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re index 0014616..bef9e21 100644 --- a/src/ApolloClient__ApolloClient.re +++ b/src/ApolloClient__ApolloClient.re @@ -16,7 +16,7 @@ module QueryOptions = ApolloClient__Core_WatchQueryOptions.QueryOptions; module PureQueryOptions = ApolloClient__Core_Types.PureQueryOptions; module RefetchQueryDescription = ApolloClient__Core_WatchQueryOptions.RefetchQueryDescription; module Resolvers = ApolloClient__Core_Types.Resolvers; -module UriFunction = ApolloClient_SelectHttpOptionsAndBody.UriFunction; +module UriFunction = ApolloClient_Link_Http_SelectHttpOptionsAndBody.UriFunction; module Types = ApolloClient__Types; module WatchQueryFetchPolicy = ApolloClient__Core_WatchQueryOptions.WatchQueryFetchPolicy; module WatchQueryOptions = ApolloClient__Core_WatchQueryOptions.QueryOptions; diff --git a/src/_notDependencies/@apollo/link-ws/ApolloLinkWs.re b/src/_notDependencies/@apollo/link-ws/ApolloLinkWs.re new file mode 100644 index 0000000..a9c5a43 --- /dev/null +++ b/src/_notDependencies/@apollo/link-ws/ApolloLinkWs.re @@ -0,0 +1,69 @@ +module ApolloLink = ApolloClient__Link_Core_ApolloLink; +module ClientOptions = SubscriptionsTransportWs.ClientOptions; +module SubscriptionClient = SubscriptionsTransportWs.SubscriptionClient; + +module WebSocketLink = { + module Configuration = { + module Js_ = { + // export declare namespace WebSocketLink { + // interface Configuration { + // uri: string; + // options?: ClientOptions; + // webSocketImpl?: any; + // } + // } + type any; + type t = { + uri: string, + options: option(ClientOptions.Js_.t), + webSocketImpl: option(any), + }; + }; + + type t = Js_.t; + }; + + module Js_ = { + // export declare class WebSocketLink extends ApolloLink { + // private subscriptionClient; + // constructor(paramsOrClient: WebSocketLink.Configuration | SubscriptionClient); + // request(operation: Operation): Observable | null; + // } + [@bs.module "@apollo/link-ws"] [@bs.new] + external make: + ( + [@bs.unwrap] + [ + | `Configuration(Configuration.Js_.t) + | `SubscriptionClient(SubscriptionClient.Js_.t) + ] + ) => + ApolloLink.Js_.t = + "WebSocketLink"; + }; + + type webSocketImpl = Configuration.Js_.any; + + let make_withConfiguration: + ( + ~uri: string, + ~options: ClientOptions.t=?, + ~webSocketImpl: webSocketImpl=?, + unit + ) => + ApolloLink.t = + (~uri, ~options=?, ~webSocketImpl=?, ()) => { + Js_.make( + `Configuration({ + uri, + options: options->Belt.Option.map(ClientOptions.toJs), + webSocketImpl, + }), + ); + }; + + let make_withSubscriptionClient: SubscriptionClient.t => ApolloLink.t = + subscriptionClient => { + Js_.make(`SubscriptionClient(subscriptionClient)); + }; +}; diff --git a/src/_notDependencies/subscriptions-transport-ws/SubscriptionsTransportWs.re b/src/_notDependencies/subscriptions-transport-ws/SubscriptionsTransportWs.re new file mode 100644 index 0000000..cb14659 --- /dev/null +++ b/src/_notDependencies/subscriptions-transport-ws/SubscriptionsTransportWs.re @@ -0,0 +1,170 @@ +// import { ListenerFn } from 'eventemitter3'; +// import { ExecutionResult } from 'graphql/execution/execute'; +// import { DocumentNode } from 'graphql/language/ast'; +// export interface Observer { +// next?: (value: T) => void; +// error?: (error: Error) => void; +// complete?: () => void; +// } +// export interface Observable { +// subscribe(observer: Observer): { +// unsubscribe: () => void; +// }; +// } +// export interface OperationOptions { +// query?: string | DocumentNode; +// variables?: Object; +// operationName?: string; +// [key: string]: any; +// } +// export declare type FormatedError = Error & { +// originalError?: any; +// }; +// export interface Operation { +// options: OperationOptions; +// handler: (error: Error[], result?: any) => void; +// } +// export interface Operations { +// [id: string]: Operation; +// } +// export interface Middleware { +// applyMiddleware(options: OperationOptions, next: Function): void; +// } +module ConnectionParams = { + module Js_ = { + // export declare type ConnectionParams = { + // [paramName: string]: any; + // }; + type t = Js.Json.t; + }; + + type t = Js_.t; +}; + +module ConnectionParamsOptions = { + module Js_ = { + module Union: { + type t; + let connectionParams: ConnectionParams.Js_.t => t; + let fn: (unit => ConnectionParams.Js_.t) => t; + let promise: Js.Promise.t(ConnectionParams.Js_.t) => t; + } = { + [@unboxed] + type t = + | Any('a): t; + let connectionParams = (v: ConnectionParams.Js_.t) => Any(v); + let fn = (v: unit => ConnectionParams.Js_.t) => Any(v); + let promise = (v: Js.Promise.t(ConnectionParams.Js_.t)) => Any(v); + }; + // export declare type ConnectionParamsOptions = ConnectionParams | Function | Promise; + type t = Union.t; + }; + + type t = + | ConnectionParams(ConnectionParams.t) + | Function(unit => ConnectionParams.t) + | Promise(Js.Promise.t(ConnectionParams.t)); + + let toJs: t => Js_.t = + fun + | ConnectionParams(v) => Js_.Union.connectionParams(v) + | Function(v) => Js_.Union.fn(v) + | Promise(v) => Js_.Union.promise(v); +}; + +module ClientOptions = { + module Js_ = { + // export interface ClientOptions { + // connectionParams?: ConnectionParamsOptions; + // timeout?: number; + // reconnect?: boolean; + // reconnectionAttempts?: number; + // connectionCallback?: (error: Error[], result?: any) => void; + // lazy?: boolean; + // inactivityTimeout?: number; + // } + type t = { + connectionParams: option(ConnectionParamsOptions.Js_.t), + timeout: option(int), + reconnect: option(bool), + reconnectionAttempts: option(int), + connectionCallback: + option( + (~error: array(Js.Exn.t), ~result: option(Js.Json.t)) => unit, + ), + [@bs.as "lazy"] + lazy_: option(bool), + inactivityTimeout: option(int), + }; + }; + + type t = { + connectionParams: option(ConnectionParamsOptions.t), + timeout: option(int), + reconnect: option(bool), + reconnectionAttempts: option(int), + connectionCallback: + option((~error: array(Js.Exn.t), ~result: option(Js.Json.t)) => unit), + [@bs.as "lazy"] + lazy_: option(bool), + inactivityTimeout: option(int), + }; + + let toJs: t => Js_.t = + t => { + connectionParams: + t.connectionParams->Belt.Option.map(ConnectionParamsOptions.toJs), + timeout: t.timeout, + reconnect: t.reconnect, + reconnectionAttempts: t.reconnectionAttempts, + connectionCallback: t.connectionCallback, + lazy_: t.lazy_, + inactivityTimeout: t.inactivityTimeout, + }; + + let make = + ( + ~connectionParams=?, + ~timeout=?, + ~reconnect=?, + ~reconnectionAttempts=?, + ~connectionCallback=?, + ~lazy_=?, + ~inactivityTimeout=?, + (), + ) + : t => { + connectionParams, + timeout, + reconnect, + reconnectionAttempts, + connectionCallback, + lazy_, + inactivityTimeout, + }; +}; + +module SubscriptionClient = { + module Js_ = { + // export declare class SubscriptionClient { + // client: any; + // operations: Operations; + // constructor(url: string, options?: ClientOptions, webSocketImpl?: any, webSocketProtocols?: string | string[]); + // readonly status: any; + // close(isForced?: boolean, closedByUser?: boolean): void; + // request(request: OperationOptions): Observable; + // on(eventName: string, callback: ListenerFn, context?: any): Function; + // onConnected(callback: ListenerFn, context?: any): Function; + // onConnecting(callback: ListenerFn, context?: any): Function; + // onDisconnected(callback: ListenerFn, context?: any): Function; + // onReconnected(callback: ListenerFn, context?: any): Function; + // onReconnecting(callback: ListenerFn, context?: any): Function; + // onError(callback: ListenerFn, context?: any): Function; + // unsubscribeAll(): void; + // applyMiddlewares(options: OperationOptions): Promise; + // use(middlewares: Middleware[]): SubscriptionClient; + // } + type t; + }; + type t = Js_.t; +}; diff --git a/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language.re b/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language.re index 5bdad1d..4df1af3 100644 --- a/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language.re +++ b/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language.re @@ -1 +1,3 @@ +module Ast = ApolloClient__Graphql_Language_Ast; + type documentNode; diff --git a/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Ast.re b/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Ast.re index 95d803b..ea567b1 100644 --- a/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Ast.re +++ b/src/_peerDependencies/graphql/language/ApolloClient__Graphql_Language_Ast.re @@ -138,3 +138,40 @@ module FragmentDefinitionNode = { selectionSet: SelectionSetNode.t, }; }; + +module VariableNode = { + type t = { + kind: string, + loc: option(Location.t), + name: NameNode.t, + }; +}; + +module VariableDefinitionNode = { + type t = { + kind: string, + loc: option(Location.t), + variable: VariableNode.t, + // [@bs.as "type"] + // type_: TypeNode.t, + defaultValue: option(ValueNode.t), + directives: option(array(DirectiveNode.t)), + }; +}; + +module OperationTypeNode = { + // export type OperationTypeNode = 'query' | 'mutation' | 'subscription'; + type t = string; +}; + +module OperationDefinitionNode = { + type t = { + kind: string, + loc: option(Location.t), + name: NameNode.t, + operation: OperationTypeNode.t, + variableDefinitions: option(array(VariableDefinitionNode.t)), + directives: option(array(DirectiveNode.t)), + selectionSet: SelectionSetNode.t, + }; +}; diff --git a/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re b/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re new file mode 100644 index 0000000..0066efb --- /dev/null +++ b/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re @@ -0,0 +1,66 @@ +module KeyFieldsFunction = ApolloClient__Cache_InMemory_Policies.KeyFieldsFunction; +module PossibleTypesMap = ApolloClient__Cache_InMemory_Policies.PossibleTypesMap; +module TypePolicies = ApolloClient__Cache_InMemory_Policies.TypePolicies; + +module InMemoryCacheConfig = { + module Js_ = { + // export interface InMemoryCacheConfig extends ApolloReducerConfig { + // resultCaching?: boolean; + // possibleTypes?: PossibleTypesMap; + // typePolicies?: TypePolicies; + // } + type t = { + resultCaching: option(bool), + possibleTypes: option(PossibleTypesMap.Js_.t), + typePolicies: option(TypePolicies.Js_.t), + // ...extends ApolloReducerConfig + dataIdFromObject: option(KeyFieldsFunction.Js_.t), + addTypename: option(bool), + }; + }; + type t = Js_.t; +}; + +module Js_ = { + // export declare class InMemoryCache extends ApolloCache { + // private data; + // private optimisticData; + // protected config: InMemoryCacheConfig; + // private watches; + // private addTypename; + // private typenameDocumentCache; + // private storeReader; + // private storeWriter; + // readonly policies: Policies; + // constructor(config?: InMemoryCacheConfig); + // restore(data: NormalizedCacheObject): this; + // extract(optimistic?: boolean): NormalizedCacheObject; + // read(options: Cache.ReadOptions): T | null; + // write(options: Cache.WriteOptions): void; + // diff(options: Cache.DiffOptions): Cache.DiffResult; + // watch(watch: Cache.WatchOptions): () => void; + // gc(): string[]; + // retain(rootId: string, optimistic?: boolean): number; + // release(rootId: string, optimistic?: boolean): number; + // identify(object: StoreObject): string | undefined; + // evict(idOrOptions: string | Cache.EvictOptions, fieldName?: string, args?: Record): boolean; + // reset(): Promise; + // removeOptimistic(idToRemove: string): void; + // private txCount; + // performTransaction(transaction: (cache: InMemoryCache) => any, optimisticId?: string): void; + // recordOptimisticTransaction(transaction: Transaction, id: string): void; + // transformDocument(document: DocumentNode): DocumentNode; + // protected broadcastWatches(): void; + // private maybeBroadcastWatch; + // private varDep; + // makeVar(value: T): ReactiveVar; + // } + type t; + + [@bs.module "@apollo/client"] + external make: InMemoryCacheConfig.Js_.t => t = "InMemoryCache"; +}; + +type t = Js_.t; + +let make: InMemoryCacheConfig.t => t = Js_.make; diff --git a/src/cache/inmemory/ApolloClient__Cache_InMemory_Policies.re b/src/cache/inmemory/ApolloClient__Cache_InMemory_Policies.re new file mode 100644 index 0000000..213242e --- /dev/null +++ b/src/cache/inmemory/ApolloClient__Cache_InMemory_Policies.re @@ -0,0 +1,71 @@ +module FragmentMap = ApolloClient__Utilities_Graphql_Fragments.FragmentMap; +module SelectionSetNode = ApolloClient__Graphql_Language_Ast.SelectionSetNode; + +module KeyFieldsContext = { + module Js_ = { + // declare type KeyFieldsContext = { + // typename?: string; + // selectionSet?: SelectionSetNode; + // fragmentMap?: FragmentMap; + // keyObject?: Record; + // }; + type t = { + typename: option(string), + selectionSet: option(SelectionSetNode.t), + fragment: option(FragmentMap.t), + keyObject: option(Js.Json.t), + }; + }; + + type t = Js_.t; +}; + +module KeyFieldsFunction = { + module Js_ = { + // export declare type KeyFieldsFunction = (object: Readonly, context: KeyFieldsContext) => KeySpecifier | ReturnType; + type t = (Js.Json.t, KeyFieldsContext.t) => string; + }; + + type t = Js_.t; +}; + +// export declare const defaultDataIdFromObject: KeyFieldsFunction; +[@bs.module "@apollo/client"] +external defaultDataIdFromObject: KeyFieldsFunction.t = + "defaultDataIdFromObject"; + +module TypePolicy = { + module Js_ = { + // export declare type TypePolicy = { + // keyFields?: KeySpecifier | KeyFieldsFunction | false; + // queryType?: true; + // mutationType?: true; + // subscriptionType?: true; + // fields?: { + // [fieldName: string]: FieldPolicy | FieldReadFunction; + // }; + // }; + type t; + }; + type t = Js_.t; +}; + +module TypePolicies = { + module Js_ = { + // export declare type TypePolicies = { + // [__typename: string]: TypePolicy; + // }; + type t = Js.Dict.t(TypePolicy.t); + }; +}; + +module PossibleTypesMap = { + module Js_ = { + // export declare type PossibleTypesMap = { + // [supertype: string]: string[]; + // }; + type t = Js.Dict.t(array(string)); + }; + + type t = Js_.t; +}; diff --git a/src/link/core/ApolloClient__Link_Core_ApolloLink.re b/src/link/core/ApolloClient__Link_Core_ApolloLink.re index 161434f..1b7234a 100644 --- a/src/link/core/ApolloClient__Link_Core_ApolloLink.re +++ b/src/link/core/ApolloClient__Link_Core_ApolloLink.re @@ -1,7 +1,8 @@ +module FetchResult = ApolloClient__Link_Core_Types.FetchResult; +module GraphQLRequest = ApolloClient__Link_Core_Types.GraphQLRequest; +module Observable = ApolloClient__ZenObservable.Observable; module Operation = ApolloClient__Link_Core_Types.Operation; module RequestHandler = ApolloClient__Link_Core_Types.RequestHandler; -// import { Observable } from '../../utilities/observables/Observable'; -// import { NextLink, Operation, RequestHandler, FetchResult, GraphQLRequest } from './types'; module Js_ = { // export declare class ApolloLink { @@ -19,6 +20,27 @@ module Js_ = { // } type t; + module Static = { + // static empty(): ApolloLink; + [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + external empty: unit => t = "empty"; + // static from(links: (ApolloLink | RequestHandler)[]): ApolloLink; + [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + external from: array(t) => t = "from"; + // static split(test: (op: Operation) => boolean, left: ApolloLink | RequestHandler, right?: ApolloLink | RequestHandler): ApolloLink; + [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + external split: (~test: Operation.Js_.t => bool, ~left: t, ~right: t) => t = + "split"; + // static execute(link: ApolloLink, operation: GraphQLRequest): Observable; + [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + external execute: + (t, GraphQLRequest.t) => Observable.t(FetchResult.Js_.t(Js.Json.t)) = + "execute"; + // static concat(first: ApolloLink | RequestHandler, second: ApolloLink | RequestHandler): ApolloLink; + [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + external concat: (t, t) => t = "concat"; + }; + [@bs.module "@apollo/client"] [@bs.new] external make: RequestHandler.Js_.t => t = "ApolloClient"; @@ -33,6 +55,8 @@ module Js_ = { "split"; }; +module Static = Js_.Static; + type t = Js_.t; let make: RequestHandler.t => t = Js_.make; @@ -43,4 +67,4 @@ let from = Js_.from; let setOnError = Js_.setOnError; -let split = Js_.split; +let split: (t, ~test: Operation.t => bool, ~left: t, ~right: t) => t = Js_.split; diff --git a/src/link/core/ApolloClient__Link_Core_Types.re b/src/link/core/ApolloClient__Link_Core_Types.re index 51c1bf0..579c133 100644 --- a/src/link/core/ApolloClient__Link_Core_Types.re +++ b/src/link/core/ApolloClient__Link_Core_Types.re @@ -2,6 +2,27 @@ module Graphql = ApolloClient__Graphql; module GraphQLError = ApolloClient__Graphql_Error_GraphQLError; module Observable = ApolloClient__ZenObservable.Observable; +module GraphQLRequest = { + module Js_ = { + // export interface GraphQLRequest { + // query: DocumentNode; + // variables?: Record; + // operationName?: string; + // context?: Record; + // extensions?: Record; + // } + type t = { + query: Graphql.documentNode, + variables: option(Js.Json.t), + operationName: option(string), + context: option(Js.Json.t), + extensions: option(Js.Json.t), + }; + }; + + type t = Js_.t; +}; + module Operation = { module Js_ = { // export interface Operation { @@ -35,8 +56,7 @@ module FetchResult = { // context?: C; // } type t('jsData) = { - // TODO: option(Js.nullable('jsData)) - data: option('jsData), + data: Js.Nullable.t('jsData), extensions: option(Js.Json.t), // ACTUAL: Record context: option(Js.Json.t), // ACTUAL: Record // ...extends ExecutionResult @@ -57,7 +77,7 @@ module FetchResult = { t('data) = (js, ~parse) => { { - data: js.data->Belt.Option.map(parse), + data: js.data->Js.toOption->Belt.Option.map(parse), extensions: js.extensions, context: js.context, errors: js.errors, diff --git a/src/link/http/ApolloClient_Link_Http_CreateHttpLink.re b/src/link/http/ApolloClient_Link_Http_CreateHttpLink.re new file mode 100644 index 0000000..9c9571b --- /dev/null +++ b/src/link/http/ApolloClient_Link_Http_CreateHttpLink.re @@ -0,0 +1,10 @@ +module ApolloLink = ApolloClient__Link_Core_ApolloLink; +module HttpOptions = ApolloClient_Link_Http_SelectHttpOptionsAndBody.HttpOptions; + +module Js_ = { + [@bs.module "@apollo/client"] + external createHttpLink: HttpOptions.Js_.t => ApolloLink.Js_.t = + "createHttpLink"; +}; + +let createHttpLink: HttpOptions.t => ApolloLink.t = Js_.createHttpLink; diff --git a/src/link/http/ApolloClient_Link_Http_HttpLink.re b/src/link/http/ApolloClient_Link_Http_HttpLink.re new file mode 100644 index 0000000..ac843dd --- /dev/null +++ b/src/link/http/ApolloClient_Link_Http_HttpLink.re @@ -0,0 +1,14 @@ +module ApolloLink = ApolloClient__Link_Core_ApolloLink; +module HttpOptions = ApolloClient_Link_Http_SelectHttpOptionsAndBody.HttpOptions; + +module Js_ = { + // export declare class HttpLink extends ApolloLink { + // options: HttpOptions; + // requester: RequestHandler; + // constructor(options?: HttpOptions); + // } + [@bs.module "@apollo/client"] [@bs.new] + external make: HttpOptions.Js_.t => ApolloLink.Js_.t = "HttpLink"; +}; + +let make: HttpOptions.t => ApolloLink.t = Js_.make; diff --git a/src/link/http/ApolloClient_SelectHttpOptionsAndBody.re b/src/link/http/ApolloClient_Link_Http_SelectHttpOptionsAndBody.re similarity index 66% rename from src/link/http/ApolloClient_SelectHttpOptionsAndBody.re rename to src/link/http/ApolloClient_Link_Http_SelectHttpOptionsAndBody.re index 8c83923..8c51906 100644 --- a/src/link/http/ApolloClient_SelectHttpOptionsAndBody.re +++ b/src/link/http/ApolloClient_Link_Http_SelectHttpOptionsAndBody.re @@ -7,6 +7,41 @@ module Operation = ApolloClient__Link_Core_Types.Operation; // variables?: Record; // extensions?: Record; // } + +module UriFunction = { + module Js_ = { + type t = Operation.Js_.t => string; + }; + + type t = Js_.t; +}; + +module HttpOptions = { + module Js_ = { + // export interface HttpOptions { + // uri?: string | UriFunction; + // includeExtensions?: boolean; + // fetch?: WindowOrWorkerGlobalScope['fetch']; + // headers?: any; + // credentials?: string; + // fetchOptions?: any; + // useGETForQueries?: boolean; + // } + type t_fetch; + + type t = { + uri: option(UriFunction.Js_.t), + includeExtensions: option(bool), + fetch: option(t_fetch), + headers: option(Js.Json.t), + credentials: option(string), + fetchOptions: Js.Json.t, + useGETForQueries: option(bool), + }; + }; + + type t = Js_.t; +}; // export interface HttpOptions { // uri?: string | UriFunction; // includeExtensions?: boolean; @@ -41,10 +76,4 @@ module Operation = ApolloClient__Link_Core_Types.Operation; // body: Body; // }; -module UriFunction = { - module Js_ = { - type t = Operation.Js_.t => string; - }; - - type t = Js_.t; -}; +(); diff --git a/src/utilities/ApolloClient__Utilities.re b/src/utilities/ApolloClient__Utilities.re new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/utilities/ApolloClient__Utilities.re @@ -0,0 +1 @@ + diff --git a/src/utilities/ApolloClient__Utilities_Graphql_Fragments.re b/src/utilities/graphql/ApolloClient__Utilities_Graphql_Fragments.re similarity index 100% rename from src/utilities/ApolloClient__Utilities_Graphql_Fragments.re rename to src/utilities/graphql/ApolloClient__Utilities_Graphql_Fragments.re diff --git a/src/utilities/graphql/ApolloClient__Utilities_Graphql_GetFromAst.re b/src/utilities/graphql/ApolloClient__Utilities_Graphql_GetFromAst.re new file mode 100644 index 0000000..91b57f2 --- /dev/null +++ b/src/utilities/graphql/ApolloClient__Utilities_Graphql_GetFromAst.re @@ -0,0 +1,7 @@ +module Graphql = ApolloClient__Graphql; + +[@bs.module "@apollo/client/utilities"] +external getOperationDefinition: + Graphql.documentNode => + option(Graphql.Language.Ast.OperationDefinitionNode.t) = + "getOperationDefinition"; From 9bae5fa255a27361c89a9e33ff6f4eb3baa3ace4 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sat, 6 Jun 2020 15:29:52 -0500 Subject: [PATCH 15/21] refactor: add separate functions for no required variables --- src/ApolloClient.re | 4 +- src/ApolloClient__ApolloClient.re | 2 +- src/core/ApolloClient__Core_Types.re | 2 +- .../ApolloClient__Core_WatchQueryOptions.re | 2 +- .../core/ApolloClient__Link_Core_Types.re | 5 +- .../hooks/ApolloClient__React_UseQuery.re | 121 +++++++++++++++--- .../ApolloClient__React_UseSubscription.re | 81 ++++++++++-- src/reason/ApolloClient__Reason.re | 2 + .../ApolloClient__Reason_Types.re} | 5 - .../ApolloClient__Reason_Utils.re} | 5 + 10 files changed, 191 insertions(+), 38 deletions(-) create mode 100644 src/reason/ApolloClient__Reason.re rename src/{ApolloClient__Types.re => reason/ApolloClient__Reason_Types.re} (69%) rename src/{ApolloClient__Utils.re => reason/ApolloClient__Reason_Utils.re} (79%) diff --git a/src/ApolloClient.re b/src/ApolloClient.re index 1803d87..68be9db 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -58,6 +58,8 @@ let useSubscription = ApolloClient__React_UseSubscription.useSubscription; // export { RenderPromises } from './react/ssr/RenderPromises.js'; module Extend = { - module UseQuery = ApolloClient__React_UseQuery.Extend; + module Query = ApolloClient__React_UseQuery.Extend; + module QueryNoRequiredVariables = ApolloClient__React_UseQuery.ExtendNoRequiredVariables; module Subscription = ApolloClient__React_UseSubscription.Extend; + module SubscriptionNoRequiredVariables = ApolloClient__React_UseSubscription.ExtendNoRequiredVariables; }; diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re index bef9e21..0df7a02 100644 --- a/src/ApolloClient__ApolloClient.re +++ b/src/ApolloClient__ApolloClient.re @@ -17,7 +17,7 @@ module PureQueryOptions = ApolloClient__Core_Types.PureQueryOptions; module RefetchQueryDescription = ApolloClient__Core_WatchQueryOptions.RefetchQueryDescription; module Resolvers = ApolloClient__Core_Types.Resolvers; module UriFunction = ApolloClient_Link_Http_SelectHttpOptionsAndBody.UriFunction; -module Types = ApolloClient__Types; +module Types = ApolloClient__Reason_Types; module WatchQueryFetchPolicy = ApolloClient__Core_WatchQueryOptions.WatchQueryFetchPolicy; module WatchQueryOptions = ApolloClient__Core_WatchQueryOptions.QueryOptions; diff --git a/src/core/ApolloClient__Core_Types.re b/src/core/ApolloClient__Core_Types.re index bcc7a4c..85e8ca0 100644 --- a/src/core/ApolloClient__Core_Types.re +++ b/src/core/ApolloClient__Core_Types.re @@ -2,7 +2,7 @@ module Graphql = ApolloClient__Graphql; module GraphqlTag = ApolloClient__GraphqlTag; module FetchResult = ApolloClient__Link_Core_Types.FetchResult; module Resolver = ApolloClient__Core_LocalState.Resolver; -module Types = ApolloClient__Types; +module Types = ApolloClient__Reason_Types; module PureQueryOptions = { module Js_ = { diff --git a/src/core/ApolloClient__Core_WatchQueryOptions.re b/src/core/ApolloClient__Core_WatchQueryOptions.re index 0035ce9..5b33d4e 100644 --- a/src/core/ApolloClient__Core_WatchQueryOptions.re +++ b/src/core/ApolloClient__Core_WatchQueryOptions.re @@ -3,7 +3,7 @@ module FetchResult = ApolloClient__Link_Core_Types.FetchResult; module GraphQL = ApolloClient__Graphql; module GraphqlTag = ApolloClient__Graphql; module MutationQueryReducersMap = ApolloClient__Core_Types.MutationQueryReducersMap; -module Types = ApolloClient__Types; +module Types = ApolloClient__Reason_Types; module PureQueryOptions = ApolloClient__Core_Types.PureQueryOptions; module ErrorPolicy = { diff --git a/src/link/core/ApolloClient__Link_Core_Types.re b/src/link/core/ApolloClient__Link_Core_Types.re index 579c133..14a1656 100644 --- a/src/link/core/ApolloClient__Link_Core_Types.re +++ b/src/link/core/ApolloClient__Link_Core_Types.re @@ -73,7 +73,10 @@ module FetchResult = { }; let fromJs: - (Js_.t('jsData), ~parse: ApolloClient__Types.parse('jsData, 'data)) => + ( + Js_.t('jsData), + ~parse: ApolloClient__Reason_Types.parse('jsData, 'data) + ) => t('data) = (js, ~parse) => { { diff --git a/src/react/hooks/ApolloClient__React_UseQuery.re b/src/react/hooks/ApolloClient__React_UseQuery.re index 58d8879..a60e5a4 100644 --- a/src/react/hooks/ApolloClient__React_UseQuery.re +++ b/src/react/hooks/ApolloClient__React_UseQuery.re @@ -4,16 +4,11 @@ module Graphql = ApolloClient__Graphql; module GraphqlTag = ApolloClient__GraphqlTag; module QueryHookOptions = ApolloClient__React_Types.QueryHookOptions; module QueryResult = ApolloClient__React_Types.QueryResult; -module Types = ApolloClient__Types; +module Types = ApolloClient__Reason_Types; module WatchQueryFetchPolicy = ApolloClient__Core_WatchQueryOptions.WatchQueryFetchPolicy; -module type Operation = ApolloClient__Types.Operation; - -type simpleQueryResult('a) = - | Data('a) - | Error(ApolloError.t) - | Loading - | NoData; +module type Operation = ApolloClient__Reason_Types.Operation; +module type OperationNoRequiredVars = ApolloClient__Reason_Types.OperationNoRequiredVars; module Js_ = { // export declare function useQuery(query: DocumentNode, options?: QueryHookOptions): QueryResult; @@ -42,7 +37,7 @@ let useQuery: ~pollInterval: int=?, ~skip: bool=?, ~ssr: bool=?, - ~variables: Types.variablesArg(jsVariables), + ~variables: jsVariables, (module Operation with type t = data and type Raw.t = jsData and @@ -62,14 +57,14 @@ let useQuery: ~pollInterval=?, ~skip=?, ~ssr=?, - ~variables as variablesArg, + ~variables, (module Definition), ) => { - let variables = - switch (variablesArg) { - | Types.NoVariables => None - | Types.Variables(v) => Some(v) - }; + // let variables = + // switch (variablesArg) { + // | Types.NoVariables => None + // | Types.Variables(v) => Some(v) + // }; let jsQueryResult = Js_.useQuery( @@ -90,13 +85,13 @@ let useQuery: query: None, skip, ssr, - variables, + variables: Some(variables), }, ~parse=Definition.parse, ), ); - ApolloClient__Utils.useGuaranteedMemo1( + ApolloClient__Reason_Utils.useGuaranteedMemo1( () => { jsQueryResult->QueryResult.fromJs( ~parse=Definition.parse, @@ -107,6 +102,63 @@ let useQuery: ); }; +let useQuery0: + type data jsData jsVariables. + ( + ~client: ApolloClient__ApolloClient.t=?, + ~context: Js.Json.t=?, + ~displayName: string=?, + ~errorPolicy: ErrorPolicy.t=?, + ~fetchPolicy: WatchQueryFetchPolicy.t=?, + ~notifyOnNetworkStatusChange: bool=?, + ~onCompleted: data => unit=?, + ~onError: ApolloError.t => unit=?, + ~partialRefetch: bool=?, + ~pollInterval: int=?, + ~skip: bool=?, + ~ssr: bool=?, + (module Types.OperationNoRequiredVars with + type t = data and + type Raw.t = jsData and + type Raw.t_variables = jsVariables) + ) => + QueryResult.t(data, jsVariables) = + ( + ~client=?, + ~context=?, + ~displayName=?, + ~errorPolicy=?, + ~fetchPolicy=?, + ~notifyOnNetworkStatusChange=?, + ~onCompleted=?, + ~onError=?, + ~partialRefetch=?, + ~pollInterval=?, + ~skip=?, + ~ssr=?, + (module Definition), + ) => { + useQuery( + ~client?, + ~context?, + ~displayName?, + ~errorPolicy?, + ~fetchPolicy?, + ~notifyOnNetworkStatusChange?, + ~onCompleted?, + ~onError?, + ~partialRefetch?, + ~pollInterval?, + ~skip?, + ~ssr?, + ~variables= + ApolloClient__Reason_Utils.nullAsDefaultVariables( + Definition.makeDefaultVariables(), + ), + (module Definition), + ); + }; + module Extend = (M: Operation) => { let use = ( @@ -143,3 +195,38 @@ module Extend = (M: Operation) => { ); }; }; + +module ExtendNoRequiredVariables = (M: OperationNoRequiredVars) => { + let use = + ( + ~client=?, + ~context=?, + ~displayName=?, + ~errorPolicy=?, + ~fetchPolicy=?, + ~notifyOnNetworkStatusChange=?, + ~onCompleted=?, + ~onError=?, + ~partialRefetch=?, + ~pollInterval=?, + ~skip=?, + ~ssr=?, + (), + ) => { + useQuery0( + ~client?, + ~context?, + ~displayName?, + ~errorPolicy?, + ~fetchPolicy?, + ~notifyOnNetworkStatusChange?, + ~onCompleted?, + ~onError?, + ~partialRefetch?, + ~pollInterval?, + ~skip?, + ~ssr?, + (module M), + ); + }; +}; diff --git a/src/react/hooks/ApolloClient__React_UseSubscription.re b/src/react/hooks/ApolloClient__React_UseSubscription.re index 6caff6b..bff1e36 100644 --- a/src/react/hooks/ApolloClient__React_UseSubscription.re +++ b/src/react/hooks/ApolloClient__React_UseSubscription.re @@ -5,9 +5,10 @@ module Graphql = ApolloClient__Graphql; module GraphqlTag = ApolloClient__GraphqlTag; module OnSubscriptionDataOptions = ApolloClient__React_Types.OnSubscriptionDataOptions; module SubscriptionHookOptions = ApolloClient__React_Types.SubscriptionHookOptions; -module Types = ApolloClient__Types; +module Types = ApolloClient__Reason_Types; -module type Operation = ApolloClient__Types.Operation; +module type Operation = ApolloClient__Reason_Types.Operation; +module type OperationNoRequiredVars = ApolloClient__Reason_Types.OperationNoRequiredVars; module Js_ = { type useSubscription_result('jsData, 'variables) = { @@ -50,7 +51,7 @@ let useSubscription: ~shouldResubscribe: BaseSubscriptionOptions.t(data, jsVariables) => bool =?, ~skip: bool=?, - ~variables: Types.variablesArg(jsVariables), + ~variables: jsVariables, (module Operation with type t = data and type Raw.t = jsData and @@ -64,14 +65,9 @@ let useSubscription: ~onSubscriptionComplete=?, ~shouldResubscribe=?, ~skip=?, - ~variables as variablesArg, + ~variables, (module Definition), ) => { - let variables = - switch (variablesArg) { - | Types.NoVariables => None - | Types.Variables(v) => Some(v) - }; let jsSubscriptionResult = Js_.useSubscription( ~subscription=GraphqlTag.gql(Definition.query), @@ -85,13 +81,13 @@ let useSubscription: subscription: None, shouldResubscribe, skip, - variables, + variables: Some(variables), }, ~parse=Definition.parse, ), ); - ApolloClient__Utils.useGuaranteedMemo1( + ApolloClient__Reason_Utils.useGuaranteedMemo1( () => { variables: jsSubscriptionResult.variables, @@ -103,6 +99,46 @@ let useSubscription: ); }; +let useSubscription0: + type data jsData jsVariables. + ( + ~client: ApolloClient__ApolloClient.t=?, + ~fetchPolicy: FetchPolicy.t=?, + ~onSubscriptionData: OnSubscriptionDataOptions.t(data) => unit=?, + ~onSubscriptionComplete: unit => unit=?, + ~shouldResubscribe: BaseSubscriptionOptions.t(data, jsVariables) => bool + =?, + ~skip: bool=?, + (module Types.OperationNoRequiredVars with + type t = data and + type Raw.t = jsData and + type Raw.t_variables = jsVariables) + ) => + useSubscription_result(data, jsVariables) = + ( + ~client=?, + ~fetchPolicy=?, + ~onSubscriptionData=?, + ~onSubscriptionComplete=?, + ~shouldResubscribe=?, + ~skip=?, + (module Definition), + ) => { + useSubscription( + ~client?, + ~fetchPolicy?, + ~onSubscriptionData?, + ~onSubscriptionComplete?, + ~shouldResubscribe?, + ~skip?, + ~variables= + ApolloClient__Reason_Utils.nullAsDefaultVariables( + Definition.makeDefaultVariables(), + ), + (module Definition), + ); + }; + module Extend = (M: Operation) => { let use = ( @@ -127,3 +163,26 @@ module Extend = (M: Operation) => { ); }; }; + +module ExtendNoRequiredVariables = (M: OperationNoRequiredVars) => { + let use = + ( + ~client=?, + ~fetchPolicy=?, + ~onSubscriptionData=?, + ~onSubscriptionComplete=?, + ~shouldResubscribe=?, + ~skip=?, + (), + ) => { + useSubscription0( + ~client?, + ~fetchPolicy?, + ~onSubscriptionData?, + ~onSubscriptionComplete?, + ~shouldResubscribe?, + ~skip?, + (module M), + ); + }; +}; diff --git a/src/reason/ApolloClient__Reason.re b/src/reason/ApolloClient__Reason.re new file mode 100644 index 0000000..f3e3c0a --- /dev/null +++ b/src/reason/ApolloClient__Reason.re @@ -0,0 +1,2 @@ +module Types = ApolloClient__Reason_Types; +module Utils = ApolloClient__Reason_Utils; diff --git a/src/ApolloClient__Types.re b/src/reason/ApolloClient__Reason_Types.re similarity index 69% rename from src/ApolloClient__Types.re rename to src/reason/ApolloClient__Reason_Types.re index caea1ec..7b1272b 100644 --- a/src/ApolloClient__Types.re +++ b/src/reason/ApolloClient__Reason_Types.re @@ -8,11 +8,6 @@ type graphqlDefinition('t, 'raw_t) = ( serialize('t, 'raw_t), ); -type variablesArg('variables) = - // Js.Json.t is the type of Raw.t_variables in graphql-ppx when there are no variables - | NoVariables: variablesArg(Js.Json.t) - | Variables('variables): variablesArg('variables); - module type Operation = { let query: string; diff --git a/src/ApolloClient__Utils.re b/src/reason/ApolloClient__Reason_Utils.re similarity index 79% rename from src/ApolloClient__Utils.re rename to src/reason/ApolloClient__Reason_Utils.re index ee9553b..5efc2c4 100644 --- a/src/ApolloClient__Utils.re +++ b/src/reason/ApolloClient__Reason_Utils.re @@ -1,3 +1,8 @@ +let nullAsDefaultVariables: 'a => 'a = + _ => { + Obj.magic(Js.Json.null); + }; + let useGuaranteedMemo1 = (f, dependency) => { let value = React.useRef(f()); let previousDependency = React.useRef(dependency); From 9fdb1adb626ce63cc41b7e5e6b82036655cafa10 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sat, 6 Jun 2020 18:21:12 -0500 Subject: [PATCH 16/21] refactor: use deriving abstract for InMemoryCacheConfig and cleanup --- src/ApolloClient__ApolloClient.re | 75 ++++++++++++++++--- ...lloClient__Cache_InMemory_InMemoryCache.re | 54 +++++++++++-- .../ApolloClient__Cache_InMemory_Policies.re | 3 +- .../ApolloClient__Link_Core_ApolloLink.re | 12 +-- .../http/ApolloClient_Link_Http_HttpLink.re | 34 ++++++++- ...ient_Link_Http_SelectHttpOptionsAndBody.re | 2 +- .../ApolloClient__React_ApolloProvider.re | 2 +- 7 files changed, 155 insertions(+), 27 deletions(-) diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re index 0df7a02..667da36 100644 --- a/src/ApolloClient__ApolloClient.re +++ b/src/ApolloClient__ApolloClient.re @@ -188,7 +188,7 @@ module ApolloClientOptions = { type t = { uri: option(UriFunction.Js_.t), credentials: option(string), - headers: Js.Dict.t(string), + headers: option(Js.Dict.t(string)), link: option(ApolloLink.Js_.t), cache: ApolloCache.Js_.t(Js.Json.t), ssrForceFetchDelay: option(int), @@ -197,8 +197,8 @@ module ApolloClientOptions = { queryDeduplication: option(bool), defaultOptions: option(DefaultOptions.Js_.t), assumeImmutableResults: option(bool), - resolvers: array(Resolvers.Js_.t), - typeDefs: array(GraphQL.documentNode), + resolvers: option(array(Resolvers.Js_.t)), + typeDefs: option(array(GraphQL.documentNode)), fragmentMatcher: option(FragmentMatcher.Js_.t), name: option(string), version: option(string), @@ -208,7 +208,7 @@ module ApolloClientOptions = { type t = { uri: option(UriFunction.t), credentials: option(string), - headers: Js.Dict.t(string), + headers: option(Js.Dict.t(string)), link: option(ApolloLink.t), cache: ApolloCache.Js_.t(Js.Json.t), ssrForceFetchDelay: option(int), @@ -217,8 +217,8 @@ module ApolloClientOptions = { queryDeduplication: option(bool), defaultOptions: option(DefaultOptions.t), assumeImmutableResults: option(bool), - resolvers: array(Resolvers.t), - typeDefs: array(GraphQL.documentNode), + resolvers: option(array(Resolvers.t)), + typeDefs: option(array(GraphQL.documentNode)), fragmentMatcher: option(FragmentMatcher.t), name: option(string), version: option(string), @@ -321,9 +321,66 @@ module Js_ = { type t = Js_.t; -let make: ApolloClientOptions.t => t = - apolloClientOptions => - Js_.make(apolloClientOptions->ApolloClientOptions.toJs); +let make: + ( + ~uri: UriFunction.t=?, + ~credentials: string=?, + ~headers: Js.Dict.t(string)=?, + ~link: ApolloLink.t=?, + ~cache: ApolloCache.Js_.t(Js.Json.t), + ~ssrForceFetchDelay: int=?, + ~ssrMode: bool=?, + ~connectToDevTools: bool=?, + ~queryDeduplication: bool=?, + ~defaultOptions: DefaultOptions.t=?, + ~assumeImmutableResults: bool=?, + ~resolvers: array(Resolvers.t)=?, + ~typeDefs: array(GraphQL.documentNode)=?, + ~fragmentMatcher: FragmentMatcher.t=?, + ~name: string=?, + ~version: string=?, + unit + ) => + t = + ( + ~uri=?, + ~credentials=?, + ~headers=?, + ~link=?, + ~cache, + ~ssrForceFetchDelay=?, + ~ssrMode=?, + ~connectToDevTools=?, + ~queryDeduplication=?, + ~defaultOptions=?, + ~assumeImmutableResults=?, + ~resolvers=?, + ~typeDefs=?, + ~fragmentMatcher=?, + ~name=?, + ~version=?, + (), + ) => + Js_.make( + ApolloClientOptions.toJs({ + uri, + credentials, + headers, + link, + cache, + ssrForceFetchDelay, + ssrMode, + connectToDevTools, + queryDeduplication, + defaultOptions, + assumeImmutableResults, + resolvers, + typeDefs, + fragmentMatcher, + name, + version, + }), + ); let mutate: type data variables jsData jsVariables. diff --git a/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re b/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re index 0066efb..1a07a3c 100644 --- a/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re +++ b/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re @@ -9,16 +9,24 @@ module InMemoryCacheConfig = { // possibleTypes?: PossibleTypesMap; // typePolicies?: TypePolicies; // } + // NOTE: Using deriving abstract here because passing properties that are undefined has effects + [@bs.deriving abstract] type t = { - resultCaching: option(bool), - possibleTypes: option(PossibleTypesMap.Js_.t), - typePolicies: option(TypePolicies.Js_.t), + [@bs.optional] + resultCaching: bool, + [@bs.optional] + possibleTypes: PossibleTypesMap.Js_.t, + [@bs.optional] + typePolicies: TypePolicies.Js_.t, // ...extends ApolloReducerConfig - dataIdFromObject: option(KeyFieldsFunction.Js_.t), - addTypename: option(bool), + [@bs.optional] + dataIdFromObject: KeyFieldsFunction.Js_.t, + [@bs.optional] + addTypename: bool, }; }; type t = Js_.t; + let make = Js_.t; }; module Js_ = { @@ -55,12 +63,42 @@ module Js_ = { // private varDep; // makeVar(value: T): ReactiveVar; // } - type t; + type t = ApolloClient__Cache_Core_Cache.ApolloCache.Js_.t(Js.Json.t); - [@bs.module "@apollo/client"] + [@bs.module "@apollo/client"] [@bs.new] external make: InMemoryCacheConfig.Js_.t => t = "InMemoryCache"; }; type t = Js_.t; -let make: InMemoryCacheConfig.t => t = Js_.make; +let make: + ( + ~resultCaching: bool=?, + ~possibleTypes: PossibleTypesMap.t=?, + ~typePolicies: TypePolicies.t=?, + ~dataIdFromObject: KeyFieldsFunction.t=?, + ~addTypename: bool=?, + unit + ) => + t = + ( + ~resultCaching=?, + ~possibleTypes=?, + ~typePolicies=?, + ~dataIdFromObject=?, + ~addTypename=?, + (), + ) => { + let config = + InMemoryCacheConfig.make( + ~resultCaching?, + ~possibleTypes?, + ~typePolicies?, + ~dataIdFromObject?, + ~addTypename?, + (), + ); + + Js.log2("config", config); + Js_.make(config); + }; diff --git a/src/cache/inmemory/ApolloClient__Cache_InMemory_Policies.re b/src/cache/inmemory/ApolloClient__Cache_InMemory_Policies.re index 213242e..995dd2f 100644 --- a/src/cache/inmemory/ApolloClient__Cache_InMemory_Policies.re +++ b/src/cache/inmemory/ApolloClient__Cache_InMemory_Policies.re @@ -55,8 +55,9 @@ module TypePolicies = { // export declare type TypePolicies = { // [__typename: string]: TypePolicy; // }; - type t = Js.Dict.t(TypePolicy.t); + type t = Js.Dict.t(TypePolicy.Js_.t); }; + type t = Js_.t; }; module PossibleTypesMap = { diff --git a/src/link/core/ApolloClient__Link_Core_ApolloLink.re b/src/link/core/ApolloClient__Link_Core_ApolloLink.re index 1b7234a..77d4df3 100644 --- a/src/link/core/ApolloClient__Link_Core_ApolloLink.re +++ b/src/link/core/ApolloClient__Link_Core_ApolloLink.re @@ -22,27 +22,27 @@ module Js_ = { module Static = { // static empty(): ApolloLink; - [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + [@bs.module "@apollo/client"] [@bs.scope "ApolloLink"] external empty: unit => t = "empty"; // static from(links: (ApolloLink | RequestHandler)[]): ApolloLink; - [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + [@bs.module "@apollo/client"] [@bs.scope "ApolloLink"] external from: array(t) => t = "from"; // static split(test: (op: Operation) => boolean, left: ApolloLink | RequestHandler, right?: ApolloLink | RequestHandler): ApolloLink; - [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + [@bs.module "@apollo/client"] [@bs.scope "ApolloLink"] external split: (~test: Operation.Js_.t => bool, ~left: t, ~right: t) => t = "split"; // static execute(link: ApolloLink, operation: GraphQLRequest): Observable; - [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + [@bs.module "@apollo/client"] [@bs.scope "ApolloLink"] external execute: (t, GraphQLRequest.t) => Observable.t(FetchResult.Js_.t(Js.Json.t)) = "execute"; // static concat(first: ApolloLink | RequestHandler, second: ApolloLink | RequestHandler): ApolloLink; - [@bs.module "@apollo/client"] [@bs.scope "ApolloClient"] + [@bs.module "@apollo/client"] [@bs.scope "ApolloLink"] external concat: (t, t) => t = "concat"; }; [@bs.module "@apollo/client"] [@bs.new] - external make: RequestHandler.Js_.t => t = "ApolloClient"; + external make: RequestHandler.Js_.t => t = "ApolloLink"; [@bs.send] external concat: (t, t) => t = "concat"; diff --git a/src/link/http/ApolloClient_Link_Http_HttpLink.re b/src/link/http/ApolloClient_Link_Http_HttpLink.re index ac843dd..6c13a72 100644 --- a/src/link/http/ApolloClient_Link_Http_HttpLink.re +++ b/src/link/http/ApolloClient_Link_Http_HttpLink.re @@ -1,5 +1,6 @@ module ApolloLink = ApolloClient__Link_Core_ApolloLink; module HttpOptions = ApolloClient_Link_Http_SelectHttpOptionsAndBody.HttpOptions; +module UriFunction = ApolloClient_Link_Http_SelectHttpOptionsAndBody.UriFunction; module Js_ = { // export declare class HttpLink extends ApolloLink { @@ -11,4 +12,35 @@ module Js_ = { external make: HttpOptions.Js_.t => ApolloLink.Js_.t = "HttpLink"; }; -let make: HttpOptions.t => ApolloLink.t = Js_.make; +let make: + ( + ~uri: UriFunction.t=?, + ~includeExtensions: bool=?, + ~fetch: HttpOptions.Js_.t_fetch=?, + ~headers: Js.Json.t=?, + ~credentials: string=?, + ~fetchOptions: Js.Json.t=?, + ~useGETForQueries: bool=?, + unit + ) => + ApolloLink.t = + ( + ~uri=?, + ~includeExtensions=?, + ~fetch=?, + ~headers=?, + ~credentials=?, + ~fetchOptions=?, + ~useGETForQueries=?, + (), + ) => { + Js_.make({ + uri, + includeExtensions, + fetch, + headers, + credentials, + fetchOptions, + useGETForQueries, + }); + }; diff --git a/src/link/http/ApolloClient_Link_Http_SelectHttpOptionsAndBody.re b/src/link/http/ApolloClient_Link_Http_SelectHttpOptionsAndBody.re index 8c51906..eeb75c8 100644 --- a/src/link/http/ApolloClient_Link_Http_SelectHttpOptionsAndBody.re +++ b/src/link/http/ApolloClient_Link_Http_SelectHttpOptionsAndBody.re @@ -35,7 +35,7 @@ module HttpOptions = { fetch: option(t_fetch), headers: option(Js.Json.t), credentials: option(string), - fetchOptions: Js.Json.t, + fetchOptions: option(Js.Json.t), useGETForQueries: option(bool), }; }; diff --git a/src/react/ApolloClient__React_ApolloProvider.re b/src/react/ApolloClient__React_ApolloProvider.re index df1ef67..6f8b5d4 100644 --- a/src/react/ApolloClient__React_ApolloProvider.re +++ b/src/react/ApolloClient__React_ApolloProvider.re @@ -3,7 +3,7 @@ // children: React.ReactNode | React.ReactNode[] | null; // } // export declare const ApolloProvider: React.FC>; -[@bs.module "@apollo/client"] +[@bs.module "@apollo/client"] [@react.component] external make: (~client: ApolloClient__ApolloClient.t, ~children: React.element) => React.element = From 12519f1099b64251ad021ea1b3cc20bf3b58551f Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sat, 6 Jun 2020 21:50:40 -0500 Subject: [PATCH 17/21] refactor: avoid option(unit) --- src/react/hooks/ApolloClient__React_UseQuery.re | 7 ++----- src/react/hooks/ApolloClient__React_UseSubscription.re | 7 ++----- src/react/types/ApolloClient__React_Types.re | 10 ++++++---- src/reason/ApolloClient__Reason_Utils.re | 5 ----- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/react/hooks/ApolloClient__React_UseQuery.re b/src/react/hooks/ApolloClient__React_UseQuery.re index a60e5a4..ca0727d 100644 --- a/src/react/hooks/ApolloClient__React_UseQuery.re +++ b/src/react/hooks/ApolloClient__React_UseQuery.re @@ -85,7 +85,7 @@ let useQuery: query: None, skip, ssr, - variables: Some(variables), + variables, }, ~parse=Definition.parse, ), @@ -151,10 +151,7 @@ let useQuery0: ~pollInterval?, ~skip?, ~ssr?, - ~variables= - ApolloClient__Reason_Utils.nullAsDefaultVariables( - Definition.makeDefaultVariables(), - ), + ~variables=Definition.makeDefaultVariables(), (module Definition), ); }; diff --git a/src/react/hooks/ApolloClient__React_UseSubscription.re b/src/react/hooks/ApolloClient__React_UseSubscription.re index bff1e36..1232bab 100644 --- a/src/react/hooks/ApolloClient__React_UseSubscription.re +++ b/src/react/hooks/ApolloClient__React_UseSubscription.re @@ -81,7 +81,7 @@ let useSubscription: subscription: None, shouldResubscribe, skip, - variables: Some(variables), + variables, }, ~parse=Definition.parse, ), @@ -131,10 +131,7 @@ let useSubscription0: ~onSubscriptionComplete?, ~shouldResubscribe?, ~skip?, - ~variables= - ApolloClient__Reason_Utils.nullAsDefaultVariables( - Definition.makeDefaultVariables(), - ), + ~variables=Definition.makeDefaultVariables(), (module Definition), ); }; diff --git a/src/react/types/ApolloClient__React_Types.re b/src/react/types/ApolloClient__React_Types.re index bee7b51..756fd74 100644 --- a/src/react/types/ApolloClient__React_Types.re +++ b/src/react/types/ApolloClient__React_Types.re @@ -29,7 +29,8 @@ module QueryHookOptions = { // INTENTIONALLY IGNORED // returnPartialData: option(bool), ssr: option(bool), - variables: option('variables), + // Intentionally restricted to not be non-optional. `option(unit)` does not compile cleanly to `undefined` + variables: 'variables, }; }; @@ -52,7 +53,7 @@ module QueryHookOptions = { // INTENTIONALLY IGNORED // returnPartialData: option(bool), ssr: option(bool), - variables: option('variables), + variables: 'variables, }; let toJs = @@ -288,7 +289,8 @@ module SubscriptionHookOptions = { type t('jsData, 'variables) = { subscription: option(Graphql.documentNode), // ...extends BaseSubscriptionOptions - variables: option('variables), + // Intentionally restricted to not be non-optional. `option(unit)` does not compile cleanly to `undefined` + variables: 'variables, fetchPolicy: option(FetchPolicy.t), shouldResubscribe: option( @@ -304,7 +306,7 @@ module SubscriptionHookOptions = { type t('data, 'variables) = { subscription: option(Graphql.documentNode), - variables: option('variables), + variables: 'variables, fetchPolicy: option(FetchPolicy.t), shouldResubscribe: option(BaseSubscriptionOptions.t('data, 'variables) => bool), diff --git a/src/reason/ApolloClient__Reason_Utils.re b/src/reason/ApolloClient__Reason_Utils.re index 5efc2c4..ee9553b 100644 --- a/src/reason/ApolloClient__Reason_Utils.re +++ b/src/reason/ApolloClient__Reason_Utils.re @@ -1,8 +1,3 @@ -let nullAsDefaultVariables: 'a => 'a = - _ => { - Obj.magic(Js.Json.null); - }; - let useGuaranteedMemo1 = (f, dependency) => { let value = React.useRef(f()); let previousDependency = React.useRef(dependency); From 1d7f9633c3f78b356f33a1b8dc6750d109c1aa35 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sat, 6 Jun 2020 21:52:38 -0500 Subject: [PATCH 18/21] refactor: rename Definition --- src/ApolloClient__ApolloClient.re | 28 +++++++++---------- .../hooks/ApolloClient__React_UseQuery.re | 16 +++++------ .../ApolloClient__React_UseSubscription.re | 14 +++++----- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re index 667da36..8c45173 100644 --- a/src/ApolloClient__ApolloClient.re +++ b/src/ApolloClient__ApolloClient.re @@ -412,7 +412,7 @@ let mutate: ~updateQueries=?, ~update=?, ~variables=?, - (module Definition), + (module Operation), ) => { Js_.mutate( client, @@ -423,21 +423,21 @@ let mutate: context, errorPolicy, fetchPolicy, - mutation: GraphqlTag.gql(Definition.query), + mutation: GraphqlTag.gql(Operation.query), optimisticResponse, updateQueries, refetchQueries, update, variables, }, - ~parse=Definition.parse, - ~serialize=Definition.serialize, + ~parse=Operation.parse, + ~serialize=Operation.serialize, ), ) ->Js.Promise.then_( jsResult => jsResult - ->FetchResult.fromJs(_, ~parse=Definition.parse) + ->FetchResult.fromJs(_, ~parse=Operation.parse) ->Js.Promise.resolve, _, ); @@ -463,14 +463,14 @@ let query: ~errorPolicy=?, ~fetchPolicy=?, ~variables=?, - (module Definition), + (module Operation), ) => { Js_.query( client, ~options= QueryOptions.toJs({ fetchPolicy, - query: GraphqlTag.gql(Definition.query), + query: GraphqlTag.gql(Operation.query), variables, errorPolicy, context, @@ -479,7 +479,7 @@ let query: ->Js.Promise.then_( jsResult => jsResult - ->ApolloQueryResult.fromJs(_, ~parse=Definition.parse) + ->ApolloQueryResult.fromJs(_, ~parse=Operation.parse) ->Js.Promise.resolve, _, ); @@ -498,14 +498,14 @@ let readQuery: type Raw.t_variables = jsVariables) ) => option(data) = - (client, ~id=?, ~optimistic=?, ~variables=?, (module Definition)) => { + (client, ~id=?, ~optimistic=?, ~variables=?, (module Operation)) => { Js_.readQuery( client, - ~options={id, query: GraphqlTag.gql(Definition.query), variables}, + ~options={id, query: GraphqlTag.gql(Operation.query), variables}, ~optimistic, ) ->Js.toOption - ->Belt.Option.map(Definition.parse); + ->Belt.Option.map(Operation.parse); }; let writeQuery: @@ -522,14 +522,14 @@ let writeQuery: type Raw.t_variables = jsVariables) ) => unit = - (client, ~broadcast=?, ~data, ~id=?, ~variables=?, (module Definition)) => { + (client, ~broadcast=?, ~data, ~id=?, ~variables=?, (module Operation)) => { Js_.writeQuery( client, ~options={ broadcast, - data: data->Definition.serialize, + data: data->Operation.serialize, id, - query: GraphqlTag.gql(Definition.query), + query: GraphqlTag.gql(Operation.query), variables, }, ); diff --git a/src/react/hooks/ApolloClient__React_UseQuery.re b/src/react/hooks/ApolloClient__React_UseQuery.re index ca0727d..3ca2278 100644 --- a/src/react/hooks/ApolloClient__React_UseQuery.re +++ b/src/react/hooks/ApolloClient__React_UseQuery.re @@ -58,7 +58,7 @@ let useQuery: ~skip=?, ~ssr=?, ~variables, - (module Definition), + (module Operation), ) => { // let variables = // switch (variablesArg) { @@ -68,7 +68,7 @@ let useQuery: let jsQueryResult = Js_.useQuery( - ~query=GraphqlTag.gql(Definition.query), + ~query=GraphqlTag.gql(Operation.query), ~options= QueryHookOptions.toJs( { @@ -87,15 +87,15 @@ let useQuery: ssr, variables, }, - ~parse=Definition.parse, + ~parse=Operation.parse, ), ); ApolloClient__Reason_Utils.useGuaranteedMemo1( () => { jsQueryResult->QueryResult.fromJs( - ~parse=Definition.parse, - ~serialize=Definition.serialize, + ~parse=Operation.parse, + ~serialize=Operation.serialize, ) }, jsQueryResult, @@ -136,7 +136,7 @@ let useQuery0: ~pollInterval=?, ~skip=?, ~ssr=?, - (module Definition), + (module Operation), ) => { useQuery( ~client?, @@ -151,8 +151,8 @@ let useQuery0: ~pollInterval?, ~skip?, ~ssr?, - ~variables=Definition.makeDefaultVariables(), - (module Definition), + ~variables=Operation.makeDefaultVariables(), + (module Operation), ); }; diff --git a/src/react/hooks/ApolloClient__React_UseSubscription.re b/src/react/hooks/ApolloClient__React_UseSubscription.re index 1232bab..4009434 100644 --- a/src/react/hooks/ApolloClient__React_UseSubscription.re +++ b/src/react/hooks/ApolloClient__React_UseSubscription.re @@ -66,11 +66,11 @@ let useSubscription: ~shouldResubscribe=?, ~skip=?, ~variables, - (module Definition), + (module Operation), ) => { let jsSubscriptionResult = Js_.useSubscription( - ~subscription=GraphqlTag.gql(Definition.query), + ~subscription=GraphqlTag.gql(Operation.query), ~options= SubscriptionHookOptions.toJs( { @@ -83,7 +83,7 @@ let useSubscription: skip, variables, }, - ~parse=Definition.parse, + ~parse=Operation.parse, ), ); @@ -92,7 +92,7 @@ let useSubscription: { variables: jsSubscriptionResult.variables, loading: jsSubscriptionResult.loading, - data: jsSubscriptionResult.data->Belt.Option.map(Definition.parse), + data: jsSubscriptionResult.data->Belt.Option.map(Operation.parse), error: jsSubscriptionResult.error, }, jsSubscriptionResult, @@ -122,7 +122,7 @@ let useSubscription0: ~onSubscriptionComplete=?, ~shouldResubscribe=?, ~skip=?, - (module Definition), + (module Operation), ) => { useSubscription( ~client?, @@ -131,8 +131,8 @@ let useSubscription0: ~onSubscriptionComplete?, ~shouldResubscribe?, ~skip?, - ~variables=Definition.makeDefaultVariables(), - (module Definition), + ~variables=Operation.makeDefaultVariables(), + (module Operation), ); }; From 4a07aa3bbfa7d36b054c374a7ce12121c9b67db0 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sun, 7 Jun 2020 12:41:51 -0500 Subject: [PATCH 19/21] refactor: explore converting exceptions to queryResult (seems terrible?) --- src/ApolloClient.re | 2 + .../@apollo/link-ws/ApolloLinkWs.re | 2 +- src/errors/ApolloClient__ApolloError.re | 41 ++++++-- .../hooks/ApolloClient__React_UseQuery.re | 95 +++++++++++-------- src/react/types/ApolloClient__React_Types.re | 49 ++++++---- src/reason/ApolloClient__Reason_Utils.re | 2 + src/utilities/ApolloClient__Utilities.re | 2 +- 7 files changed, 126 insertions(+), 67 deletions(-) diff --git a/src/ApolloClient.re b/src/ApolloClient.re index 68be9db..216dc2d 100644 --- a/src/ApolloClient.re +++ b/src/ApolloClient.re @@ -57,6 +57,8 @@ let useSubscription = ApolloClient__React_UseSubscription.useSubscription; // export { useApolloClient } from './react/hooks/useApolloClient.js'; // export { RenderPromises } from './react/ssr/RenderPromises.js'; +module Utilities = ApolloClient__Utilities; + module Extend = { module Query = ApolloClient__React_UseQuery.Extend; module QueryNoRequiredVariables = ApolloClient__React_UseQuery.ExtendNoRequiredVariables; diff --git a/src/_notDependencies/@apollo/link-ws/ApolloLinkWs.re b/src/_notDependencies/@apollo/link-ws/ApolloLinkWs.re index a9c5a43..f90af9c 100644 --- a/src/_notDependencies/@apollo/link-ws/ApolloLinkWs.re +++ b/src/_notDependencies/@apollo/link-ws/ApolloLinkWs.re @@ -44,7 +44,7 @@ module WebSocketLink = { type webSocketImpl = Configuration.Js_.any; - let make_withConfiguration: + let make: ( ~uri: string, ~options: ClientOptions.t=?, diff --git a/src/errors/ApolloClient__ApolloError.re b/src/errors/ApolloClient__ApolloError.re index 1c37db8..52799ff 100644 --- a/src/errors/ApolloClient__ApolloError.re +++ b/src/errors/ApolloClient__ApolloError.re @@ -1,14 +1,6 @@ module Graphql = ApolloClient__Graphql; module GraphQLError = Graphql.Error.GraphQLError; -// export declare class ApolloError extends Error { -// constructor({ graphQLErrors, networkError, errorMessage, extraInfo, }: { -// graphQLErrors?: ReadonlyArray; -// networkError?: Error | null; -// errorMessage?: string; -// extraInfo?: any; -// }); -// } module Js_ = { // export declare class ApolloError extends Error { // message: string; @@ -25,6 +17,39 @@ module Js_ = { message: string, stack: option(string), }; + + type make_args = { + graphQLErrors: option(array(GraphQLError.t)), + networkError: Js.nullable(Js.Exn.t), + errorMessage: option(string), + extraInfo: option(Js.Json.t), + }; + + // constructor({ graphQLErrors, networkError, errorMessage, extraInfo, }: { + // graphQLErrors?: ReadonlyArray; + // networkError?: Error | null; + // errorMessage?: string; + // extraInfo?: any; + // }); + [@bs.module "@apollo/client"] [@bs.new] + external make: make_args => t = "ApolloError"; }; type t = Js_.t; + +let make: + ( + ~graphQLErrors: array(GraphQLError.t)=?, + ~networkError: Js.Exn.t=?, + ~errorMessage: string=?, + ~extraInfo: Js.Json.t=?, + unit + ) => + t = + (~graphQLErrors=?, ~networkError=?, ~errorMessage=?, ~extraInfo=?, ()) => + Js_.make({ + graphQLErrors, + networkError: Js.Nullable.fromOption(networkError), + errorMessage, + extraInfo, + }); diff --git a/src/react/hooks/ApolloClient__React_UseQuery.re b/src/react/hooks/ApolloClient__React_UseQuery.re index 3ca2278..1145024 100644 --- a/src/react/hooks/ApolloClient__React_UseQuery.re +++ b/src/react/hooks/ApolloClient__React_UseQuery.re @@ -10,6 +10,26 @@ module WatchQueryFetchPolicy = ApolloClient__Core_WatchQueryOptions.WatchQueryFe module type Operation = ApolloClient__Reason_Types.Operation; module type OperationNoRequiredVars = ApolloClient__Reason_Types.OperationNoRequiredVars; +exception InternalReasonApolloExn; +let exceptionQueryResult = () => + QueryResult.{ + called: true, + client: Obj.magic(), + data: None, + error: + Some( + ApolloError.make( + ~errorMessage="Internal Reason Apollo Exception", + (), + ), + ), + fetchMore: + (~context as _=?, ~variables as _=?, ~updateQuery as _=?, ()) => + Js.Promise.reject(InternalReasonApolloExn), + loading: false, + networkStatus: Ready, + }; + module Js_ = { // export declare function useQuery(query: DocumentNode, options?: QueryHookOptions): QueryResult; [@bs.module "@apollo/client"] @@ -59,48 +79,45 @@ let useQuery: ~ssr=?, ~variables, (module Operation), - ) => { - // let variables = - // switch (variablesArg) { - // | Types.NoVariables => None - // | Types.Variables(v) => Some(v) - // }; + ) => + try({ + let jsQueryResult = + Js_.useQuery( + ~query=GraphqlTag.gql(Operation.query), + ~options= + QueryHookOptions.toJs( + { + client, + context, + displayName, + errorPolicy, + fetchPolicy, + onCompleted, + onError, + notifyOnNetworkStatusChange, + partialRefetch, + pollInterval, + query: None, + skip, + ssr, + variables, + }, + ~parse=Operation.parse, + ), + ); - let jsQueryResult = - Js_.useQuery( - ~query=GraphqlTag.gql(Operation.query), - ~options= - QueryHookOptions.toJs( - { - client, - context, - displayName, - errorPolicy, - fetchPolicy, - onCompleted, - onError, - notifyOnNetworkStatusChange, - partialRefetch, - pollInterval, - query: None, - skip, - ssr, - variables, - }, + ApolloClient__Reason_Utils.useGuaranteedMemo1( + () => { + jsQueryResult->QueryResult.fromJs( ~parse=Operation.parse, - ), + ~serialize=Operation.serialize, + ) + }, + jsQueryResult, ); - - ApolloClient__Reason_Utils.useGuaranteedMemo1( - () => { - jsQueryResult->QueryResult.fromJs( - ~parse=Operation.parse, - ~serialize=Operation.serialize, - ) - }, - jsQueryResult, - ); - }; + }) { + | _anyExn => exceptionQueryResult() + }; let useQuery0: type data jsData jsVariables. diff --git a/src/react/types/ApolloClient__React_Types.re b/src/react/types/ApolloClient__React_Types.re index 756fd74..f5c4143 100644 --- a/src/react/types/ApolloClient__React_Types.re +++ b/src/react/types/ApolloClient__React_Types.re @@ -87,14 +87,18 @@ module QueryResult = { type t_fetchMoreOptions('jsData, 'variables) = { query: option(Graphql.Language.documentNode), + // ...extends FetchMoreQueryOptions variables: option('variables), context: option(Js.Json.t), + // ...extends FetchMoreOptions updateQuery: - ( + option( + ( + 'jsData, + t_fetchMoreOptions_updateQueryOptions('jsData, 'variables) + ) => 'jsData, - t_fetchMoreOptions_updateQueryOptions('jsData, 'variables) - ) => - 'jsData, + ), }; // export interface QueryResult extends ObservableQueryFields { @@ -106,15 +110,16 @@ module QueryResult = { // called: true; // } type t('jsData, 'variables) = { - fetchMore: - t_fetchMoreOptions('jsData, 'variables) => - Js.Promise.t(ApolloQueryResult.t('jsData)), called: bool, client: ApolloClient__ApolloClient.t, data: option('jsData), error: option(ApolloError.t), loading: bool, networkStatus: NetworkStatus.t, + // ...extends ObservableQueryFields + fetchMore: + t_fetchMoreOptions('jsData, 'variables) => + Js.Promise.t(ApolloQueryResult.t('jsData)), }; }; @@ -134,7 +139,8 @@ module QueryResult = { 'variables, ) ) => - 'parsedData, + 'parsedData + =?, unit ) => Js.Promise.t(ApolloQueryResult.t('parsedData)), @@ -155,19 +161,26 @@ module QueryResult = { data: js.data->Belt.Option.map(parse), error: js.error, fetchMore: - (~context=?, ~variables=?, ~updateQuery as jsUpdateQuery, ()) => { + (~context=?, ~variables=?, ~updateQuery as jsUpdateQuery=?, ()) => { js.fetchMore({ context, query: None, - updateQuery: (previousResult, {fetchMoreResult, variables}) => - jsUpdateQuery( - parse(previousResult), - { - fetchMoreResult: fetchMoreResult->Belt.Option.map(parse), - variables, - }, - ) - ->serialize, + updateQuery: + jsUpdateQuery->Belt.Option.map( + ( + jsUpdateQuery, + previousResult, + Js_.{fetchMoreResult, variables}, + ) => + jsUpdateQuery( + parse(previousResult), + { + fetchMoreResult: fetchMoreResult->Belt.Option.map(parse), + variables, + }, + ) + ->serialize + ), variables, }) ->Js.Promise.then_( diff --git a/src/reason/ApolloClient__Reason_Utils.re b/src/reason/ApolloClient__Reason_Utils.re index ee9553b..06bb0cc 100644 --- a/src/reason/ApolloClient__Reason_Utils.re +++ b/src/reason/ApolloClient__Reason_Utils.re @@ -1,3 +1,5 @@ +let exceptionsAsApolloError = () => (); + let useGuaranteedMemo1 = (f, dependency) => { let value = React.useRef(f()); let previousDependency = React.useRef(dependency); diff --git a/src/utilities/ApolloClient__Utilities.re b/src/utilities/ApolloClient__Utilities.re index 8b13789..41ce668 100644 --- a/src/utilities/ApolloClient__Utilities.re +++ b/src/utilities/ApolloClient__Utilities.re @@ -1 +1 @@ - +let getOperationDefinition = ApolloClient__Utilities_Graphql_GetFromAst.getOperationDefinition; From e050eab58751bc3ed902695451df15fad7554b7a Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Sun, 7 Jun 2020 13:17:01 -0500 Subject: [PATCH 20/21] refactor: add a couple examples --- src/ApolloClient__ApolloClient.re | 12 +++ src/EXAMPLES/AMinimalClient.re | 74 +++++++++++++++++++ src/EXAMPLES/bsconfig_extension.json | 8 ++ ...lloClient__Cache_InMemory_InMemoryCache.re | 8 +- 4 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/EXAMPLES/AMinimalClient.re create mode 100644 src/EXAMPLES/bsconfig_extension.json diff --git a/src/ApolloClient__ApolloClient.re b/src/ApolloClient__ApolloClient.re index 8c45173..8a78c1a 100644 --- a/src/ApolloClient__ApolloClient.re +++ b/src/ApolloClient__ApolloClient.re @@ -47,6 +47,12 @@ module DefaultOptions = { errorPolicy: t.errorPolicy->Belt.Option.map(ErrorPolicy.toJs), context: t.context, }; + + let make = (~fetchPolicy=?, ~errorPolicy=?, ~context=?, ()) => { + fetchPolicy, + errorPolicy, + context, + }; }; module DefaultQueryOptions = { @@ -73,6 +79,12 @@ module DefaultOptions = { errorPolicy: t.errorPolicy->Belt.Option.map(ErrorPolicy.toJs), context: t.context, }; + + let make = (~fetchPolicy=?, ~errorPolicy=?, ~context=?, ()) => { + fetchPolicy, + errorPolicy, + context, + }; }; module DefaultMutationOptions = { diff --git a/src/EXAMPLES/AMinimalClient.re b/src/EXAMPLES/AMinimalClient.re new file mode 100644 index 0000000..dd68929 --- /dev/null +++ b/src/EXAMPLES/AMinimalClient.re @@ -0,0 +1,74 @@ +let graphqlEndpoint = ""; + +let headers = {"high": "five"}; + +let httpLink = + ApolloClient.HttpLink.make( + ~uri=_ => "http://" ++ graphqlEndpoint, + ~credentials="include", + ~headers=Obj.magic(headers), + (), + ); + +let wsLink = + ApolloLinkWs.( + WebSocketLink.make( + ~uri="ws://" ++ graphqlEndpoint, + ~options= + ClientOptions.make( + ~connectionParams= + ConnectionParams(Obj.magic({"headers": headers})), + ~reconnect=true, + (), + ), + (), + ) + ); + +let terminatingLink = + ApolloClient.split( + ~test= + ({query}) => { + let definition = ApolloClient.Utilities.getOperationDefinition(query); + switch (definition) { + | Some({kind, operation}) => + kind === "OperationDefinition" && operation === "subscription" + | None => false + }; + }, + ~right=httpLink, + ~left=wsLink, + ); + +let apolloClient = + ApolloClient.ApolloClient.( + make( + ~cache=ApolloClient.InMemoryCache.make(), + ~connectToDevTools=true, + ~defaultOptions= + DefaultOptions.make( + ~mutate= + DefaultOptions.DefaultMutationOptions.make( + ~awaitRefetchQueries=true, + ~fetchPolicy=NetworkOnly, + ~errorPolicy=All, + (), + ), + ~query= + DefaultOptions.DefaultQueryOptions.make( + ~fetchPolicy=NetworkOnly, + ~errorPolicy=All, + (), + ), + ~watchQuery= + DefaultOptions.DefaultWatchQueryOptions.make( + ~fetchPolicy=NetworkOnly, + ~errorPolicy=All, + (), + ), + (), + ), + ~link=terminatingLink, + (), + ) + ); diff --git a/src/EXAMPLES/bsconfig_extension.json b/src/EXAMPLES/bsconfig_extension.json new file mode 100644 index 0000000..f77b583 --- /dev/null +++ b/src/EXAMPLES/bsconfig_extension.json @@ -0,0 +1,8 @@ +{ + "graphql": { + "extend-query": "ApolloClient.Extend.Query", + "extend-query-no-required-variables": "ApolloClient.Extend.QueryNoRequiredVariables", + "extend-subscription": "ApolloClient.Extend.Subscription", + "extend-subscription-no-required-variables": "ApolloClient.Extend.SubscriptionNoRequiredVariables" + } +} diff --git a/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re b/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re index 1a07a3c..05dc4d3 100644 --- a/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re +++ b/src/cache/inmemory/ApolloClient__Cache_InMemory_InMemoryCache.re @@ -89,7 +89,7 @@ let make: ~addTypename=?, (), ) => { - let config = + Js_.make( InMemoryCacheConfig.make( ~resultCaching?, ~possibleTypes?, @@ -97,8 +97,6 @@ let make: ~dataIdFromObject?, ~addTypename?, (), - ); - - Js.log2("config", config); - Js_.make(config); + ), + ); }; From 9ee3077118b057b085590d3ee90508c222b42a05 Mon Sep 17 00:00:00 2001 From: Joel Jeddeloh Date: Fri, 19 Jun 2020 16:21:53 -0500 Subject: [PATCH 21/21] refactor: update contributing --- CONTRIBUTING.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 023d4d0..938c562 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,36 +5,34 @@ NOTE: this is just documenting my process for this PR in case anyone wants to he My hope is that we can achieve well maintained, nearly-complete bindings without a huge burden on any single person if we follow these two rules: 1. Follow a consistent pattern for bindings -1. No partial types or bindings if possible - -Let's try it and see how it works out! +1. Avoid partial types or bindings if possible ## Going the Full Distance -No single binding is _that_ much work. Please completely type something as you come across it or leave it for someone else. If all of us contribute just a little piece, but do it completely, it should be very easy to get 99% complete bindings. Also, 50% of the work is in tracing through the code and loading up context. This way no one has to go back and duplicate that work. Each binding we add also makes the next one that much faster as we have more and more types we can reuse blindly. +Please type something as completely as possible when you come across it or leave it for someone else (if nothing else, put an abstract type so things will still flow through everywhere and people can cast it). If all of us contribute just a little piece, but do it completely, it should be very easy to get 99% complete bindings. Also, 50% of the work is in tracing through the code and loading up context. This way no one has to go back and duplicate that work. Each binding we add also makes the next one that much faster as we have more and more types we can reuse blindly. # Guidelines (style) -## Module Names +## Directory Structure and File Naming ``` -@apollo/client/react/hooks/react/useQuery.js +@apollo/client/react/hooks/useQuery.js ``` should become ``` -reason-react-hooks/src/react/hooks/ApolloClient__React_UseQuery.re +reason-react-hooks/src/react/hooks/ApolloClient__React_Hooks_UseQuery.re ``` in reason. ### Breaking it down: `/[1]/[2]__[3]_[4]` -1. Modules should be located in the same directory structure as the js counterpart (usually there is a `.d.ts` for every `.js` file so we can think of them interchangeably) +1. Reason files should be located in the same directory structure as the js counterpart (usually there is a `.d.ts` for every `.js` file so we can think of them interchangeably) 1. All module names should be prefixed with `ApolloClient__` "namespace" -1. Modules should be prefixed with the nearest `.js` parent module (and exported from there as well) -1. Modules should be named the same as the js counterpart +1. File names reflect the directory structure +1. Files should be named the same as the js counterpart ## Types