@cran/gql.link.merge
TypeScript icon, indicating that this package has built-in type declarations

0.0.1 • Public • Published

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.

Readme

Keywords

Package Sidebar

Install

npm i @cran/gql.link.merge

Weekly Downloads

2

Version

0.0.1

License

CC-BY-ND-4.0

Unpacked Size

18.5 kB

Total Files

16

Last publish

Collaborators

  • common-cranberry