npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@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.