This repository has been archived by the owner on Nov 20, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 28
/
FilterByNameCache.re
108 lines (97 loc) · 3.38 KB
/
FilterByNameCache.re
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
open ApolloHooks;
/**
* Query response will be parsed using Config.parse from graphq_ppx before it is accessed in
* reason, but react-apollo will save it in cache in its original format, as a regular JS object,
* and apollo requires the data to be saved in cache in the same format or cache won't work correctly.
*
* If using directives like @bsRecord, @bsDecoder or @bsVariant on the query result, the data
* in cache and the parsed data won't to have the same format. Since there is currently no way
* to serialize the parsed data back to its initial format, queries that will be updated manually
* in cache can't use any of those directive, unless you will take care of the serialization yourself.
*/
module PersonsNameFilterQuery = [%graphql
{|
query getPersonsWithName($name: String!) {
allPersons(filter: { name: $name } ) {
id
name
age
}
}
|}
];
external cast: Js.Json.t => PersonsNameFilterQuery.t = "%identity";
type person = {
.
"age": int,
"id": string,
"name": string,
};
/** example using cache */
module PersonsNameFilterReadQuery =
ApolloClient.ReadQuery(PersonsNameFilterQuery);
module PersonsNameFilterWriteQuery =
ApolloClient.WriteQuery(PersonsNameFilterQuery);
let updateFiltered = (person: person, name, filteredPersons: array(person)) =>
person##name === name
? filteredPersons->Belt.Array.concat([|person|])
: filteredPersons->Belt.Array.keep(p => p##id !== person##id);
let updateCache = (client, person, name) => {
let filterByNameQuery = PersonsNameFilterQuery.make(~name, ());
// By default, apollo adds field __typename to the query and will use it
// to normalize data. Parsing the result with Config.parse will remove the field,
// which won't allow to save the data back to cache. This means we can't use ReadQuery.make,
// which parses cache result, and have to use the readQuery which returns Json.t.
switch (
PersonsNameFilterReadQuery.readQuery(
client,
{
query: ApolloClient.gql(. filterByNameQuery##query),
variables: Js.Nullable.return(filterByNameQuery##variables),
},
)
) {
| exception _ => ()
| cachedResponse =>
switch (cachedResponse |> Js.Nullable.toOption) {
| None => ()
| Some(cachedPersons) =>
// readQuery returns unparsed data as Json.t, but since PersonsNameFilterQuery
// is not using any graphql_ppx directive, the data will have the same format,
// (with the addition of __typename field) and can be cast to PersonsNameFilterConfig.t.
let persons = cast(cachedPersons);
let updatedPersons = {
"allPersons": updateFiltered(person, name, persons##allPersons),
};
PersonsNameFilterWriteQuery.make(
~client,
~variables=filterByNameQuery##variables,
~data=updatedPersons,
(),
);
}
};
};
[@react.component]
let make = (~name) => {
let (simple, _full) =
useQuery(
~variables=PersonsNameFilterQuery.make(~name, ())##variables,
PersonsNameFilterQuery.definition,
);
<div>
{switch (simple) {
| Loading => <p> {React.string("Loading...")} </p>
| Data(data) =>
<h3>
{"There are "
++ (data##allPersons->Belt.Array.length |> string_of_int)
++ " with name "
++ name
|> React.string}
</h3>
| NoData
| Error(_) => <p> {React.string("Error")} </p>
}}
</div>;
};