Skip to content
This repository was archived by the owner on Nov 20, 2020. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all 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
96 changes: 96 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
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. Avoid partial types or bindings if possible

## Going the Full Distance

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)

## Directory Structure and File Naming

```
@apollo/client/react/hooks/useQuery.js
```

should become

```
reason-react-hooks/src/react/hooks/ApolloClient__React_Hooks_UseQuery.re
```

in reason.

### Breaking it down: `/[1]/[2]__[3]_[4]`

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. File names reflect the directory structure
1. Files 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<TData, TVariables>) => 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
67 changes: 67 additions & 0 deletions src/ApolloClient.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 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 { 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';
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 Utilities = ApolloClient__Utilities;

module 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;
};
Loading