Skip to content
This repository has been archived by the owner on Nov 20, 2020. It is now read-only.

Apollo Client 3 Mirroring Exploration #122

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0204b18
refactor: apollo client 3 mirroring exploration
jeddeloh May 10, 2020
0931654
fix: bad copy/paste
jeddeloh May 10, 2020
d2e7695
refactor: rename `raw` stuff to `js`
jeddeloh May 18, 2020
8f82251
refactor: switch to polymorphic variants and jsConverter
jeddeloh May 18, 2020
b0b09c8
refactor: use option instead of nullable where appropriate
jeddeloh May 18, 2020
de4d6c3
refactor: add some ApolloClient bindings and switch to FCM api
jeddeloh May 24, 2020
7c6b257
fix: missed serialize in writeData
jeddeloh May 24, 2020
98675f9
refactor: add ApolloClient to main module
jeddeloh May 24, 2020
4a69308
refactor: add ApolloProvider, CONTRIBUTING file, and some cleanup
jeddeloh May 26, 2020
7d8fe73
refactor: make variables required
jeddeloh Jun 3, 2020
2becb05
refactor: add apollo link
jeddeloh Jun 5, 2020
872bd30
refactor: add defaultOptions
jeddeloh Jun 5, 2020
f03c39f
refactor: finish ApolloClient construction
jeddeloh Jun 5, 2020
1a43e5a
refactor: add HttpLink, WebSocketLink, InMemoryCache
jeddeloh Jun 6, 2020
9bae5fa
refactor: add separate functions for no required variables
jeddeloh Jun 6, 2020
9fdb1ad
refactor: use deriving abstract for InMemoryCacheConfig and cleanup
jeddeloh Jun 6, 2020
12519f1
refactor: avoid option(unit)
jeddeloh Jun 7, 2020
1d7f963
refactor: rename Definition
jeddeloh Jun 7, 2020
4a07aa3
refactor: explore converting exceptions to queryResult (seems terrible?)
jeddeloh Jun 7, 2020
e050eab
refactor: add a couple examples
jeddeloh Jun 7, 2020
9ee3077
refactor: update contributing
jeddeloh Jun 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/Apollo_Client/Apollo_Client.re
Original file line number Diff line number Diff line change
@@ -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;
1 change: 1 addition & 0 deletions src/Apollo_Client/Apollo_Client__ApolloClient.re
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
type t;
9 changes: 9 additions & 0 deletions src/Apollo_Client/Apollo_Client__Types.re
Original file line number Diff line number Diff line change
@@ -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),
);
11 changes: 11 additions & 0 deletions src/Apollo_Client/Apollo_Client__Utils.re
Original file line number Diff line number Diff line change
@@ -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;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[@bs.module "graphql-tag"]
external gql: string => Apollo_Client__Graphql_Language.documentNode =
"default";
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module GraphQLError = Apollo_Client__Graphql_Error_GraphQLError;
Original file line number Diff line number Diff line change
@@ -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
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
type documentNode;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
type sourceLocation = {
line: int,
column: int,
};
3 changes: 3 additions & 0 deletions src/Apollo_Client/core/Apollo_Client__Core.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module NetworkStatus = Apollo_Client__Core_NetworkStatus;
module Types = Apollo_Client__Core_Types;
module WatchQueryOptions = Apollo_Client__Core_WatchQueryOptions;
20 changes: 20 additions & 0 deletions src/Apollo_Client/core/Apollo_Client__Core_NetworkStatus.re
Original file line number Diff line number Diff line change
@@ -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;
27 changes: 27 additions & 0 deletions src/Apollo_Client/core/Apollo_Client__Core_Types.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module Graphql = Apollo_Client__Graphql;

module ApolloQueryResult = {
module Raw = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this also would be called JS type right? maybe we could add some comments explaining a bit more to help future contributors

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This would be JS or Js_. Now that you bring this up, I think it's possible it would be clearer to future contributors if there was a clear 1:1 Bindings module rather than mixing this stuff, but who know. I'll try a branch off this PR and see if people like that direction.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: explaining a bit more to help future contributors, I think a CONTRIBUTING.md with some explanation of patterns used might be a good goal. https://help.github.com/en/github/building-a-strong-community/setting-guidelines-for-repository-contributors

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,
};
};
32 changes: 32 additions & 0 deletions src/Apollo_Client/core/Apollo_Client__Core_WatchQueryOptions.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module ErrorPolicy = {
type t =
| None
| Ignore
| All;

let toRaw =
fun
| None => "none"
| Ignore => "ignore"
| All => "all";
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I prefer this as well, but for some reason I thought bs.deriving only worked on polymorphic variants and that this was an intentional style decision before.

Copy link
Member Author

@jeddeloh jeddeloh May 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, nevermind, I got excited and misread the docs. You do indeed need polymorphic variants, but it sounds like that's the direction we want to go (and I agree), so I'll still make the switch.


module WatchQueryFetchPolicy = {
type t =
| CacheAndNetwork
// ...extends FetchPolicy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what this means?

Copy link
Member Author

@jeddeloh jeddeloh May 17, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just saying that in typescript WatchQueryFetchPolicy only defines one value and the rest are through extending FetchPolicy. I usually try to keep properties in alphabetical order, but here I was experimenting to see if it's more useful to separate each group by what is extended. Maybe we should ignore it or make it clear what the comment is saying 😆

| 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";
};
16 changes: 16 additions & 0 deletions src/Apollo_Client/errors/Apollo_Client__Errors.re
Original file line number Diff line number Diff line change
@@ -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";
};
2 changes: 2 additions & 0 deletions src/Apollo_Client/react/Apollo_Client__React.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Types = Apollo_Client__React_Types;
let useQuery = Apollo_Client__React_UseQuery.useQuery;
99 changes: 99 additions & 0 deletions src/Apollo_Client/react/hooks/Apollo_Client__React_UseQuery.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
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)=?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think jsData could be easier to read and grasp for future contributors reading this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

) =>
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 =
switch (queryResult) {
| {loading: true} => Loading
| {error: Some(error)} => Error(error)
| {data: Some(data)} => Data(data)
| _ => NoData
};

(simple, queryResult);
},
jsQueryResult,
);
};
Loading