@cran/gql.link.merge
v0.0.1
Published
Apollo Link to Merge GQL Queries
Downloads
2
Readme
Apollo Merge Link
- Merge all Queries
- Forward all Mutations and Subscriptions
Caveats
The use of no-cache
fetch policy will
cause this link to fail. The cache is used
to re-evaluate a merged query to avoid
having to back-parse the merge. This
improves efficiency and makes the code base
smaller, but at the cost of requiring a cache.
If you wish to use the no-cache
policy, or
for any other reason do not want to merge,
provide in the context merge: false
,
which will disable this link.
This is useful for authentication or other sensitive / ephemeral data which should not be cached. This does however imply that these queries cannot be merged.
For more information about fetch policies view this article.
Initialization
import { MergeLink } from "@cran/gql.merge-link";
export const client = new ApolloLink({
cache: new InMemoryCache(),
link: from([
// apollo-link-context
new MergeLink({ client ( ) { return client; } }),
// apollo-link-retry
// apollo-link-queue
new BatchHttpLink({ uri: "0.0.0.0" }),
]),
});
Usage
Async IIFE is for example only.
If you are manually calling the client query statement, wrap any independent queries in a promise all statement, otherwise the merge link will not be effective.
// DO THIS
(async function ( ) {
const [
{ data: { a, }, },
{ data: { b, }, },
] = Promise.all([
client.query(gql`{a}`),
client.query(gql`{b}`),
]);
return [ a, b, ];
})();
// DO NOT DO THIS
(async function ( ) {
const { data: { a, }, } = await client.query({
query: gql`{a}`,
});
const { data: { b, }, } = await client.query({
query: gql`{b}`,
});
return [ a, b, ];
})();
// UNLESS DEPENDENT
(async function ( ) {
const { data: { a, }, } = await client.query({
query: gql`{a}`,
});
const { data: { b, }, } = await client.query({
query: gql`query($a:String){ b(a:$a) }`,
variables: { a, },
});
return [ a, b, ];
})();
Merge Rules
- A query must exist at the same path to be merged
- A query must have the same arguments to be merged
- Variables are not substituted for inline values
- Variables are not created for inline values
- Variables with the same value are merged
- Variable values are compared with pointer equivalence
- Aliases are merged by path, but return successfully
Queries
query { a }
query { b { a } }
query { b { c } }
query { b(a:1) { c } }
query($a:String!) { b(a:$a) { c } }
# { a: 1 }
query($b:String!) { alias:b(a:$a) { d } }
# { a: 1 }
query($b:String!) { alias:b(a:$a) { c } }
# { a: 2 }
query { auth { token } }
# context: { merge: false }
# fetchPolicy: no-cache
mutation {
update() { id }
}
Merge Result
query {
auth { token }
}
mutation {
update() { id }
}
query($a:String!,$b:String!) {
a
b { a c }
b(a:1) { c }
b(a:$a) { c d }
b(a:$b) { c }
}
# { a: 1, b: 2 }
While it may cause some confusion
here, it should be noted that variables
are created with a26 incrementing ids.
i.e. If you have 26 active variables, the
next will be labeled aa
. These variable
names are reset once a merged query is sent.
Order
If you noticed in the above example that the merged query came last, this is because the merger is debounced by 10ms (which is the same default length as the batch link). This allows time to collect queries for merging as well as ensuring mutations requested during the merge process are executed before receiving the query data.
Why 10ms?
A common cycle in the JS queue-stack is 4-5ms meaning any timeout is delayed by at least this amount. Allowing for twice this ensures that at least 1 cycle will have passed before processing the merge.