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

apollo-enchanted-cache-inmemory

v1.2.0

Published

Apollo InMemoryCache wrapper for storing selected only queries and for updating linked/nested without IDs

Downloads

20

Readme

🚀‍‍ Apollo 🧙 Enchanted InMemoryCache NPM

🚀 Apollo 🛠‍ Tool represented as InMemoryCache 🧙 wrapper for 🗄 storing / 🗃 restoring ✅ selected only 🗂️ queries and for updating ⛓ linked / nested without 🆔 IDs

Content

Install

$ npm install apollo-enchanted-cache-inmemory -S

or

$ yarn add apollo-enchanted-cache-inmemory

Usage

Creating Enchanted InMemoryCache Config

queries
// * - example for fields as variables used in a query
export const SomeQueryName = 'SomeQueryName';
export const SomeQueryResponseField = 'response';
export const SomeQueryResultField = 'result';
export const QUERY_CREATED_BY_GQL_FUNCTION = gql`
  query ${SomeQueryName} {
    ${SomeQueryResponseField}: ExampleQuery {
      ${SomeQueryResultField} {
        someDataField {
          ...ExampleFragment
        }
        ...ExampleFragment2
      }
    }
  }
  ${ExampleFragment}
  ${ExampleFragment2}
`;
// * - example for fields as variables used in a query
const SomeQueryName2 = 'SomeQueryName2';
const SomeQueryResponseField2 = 'SomeQueryResponseField2';
const SomeQueryResultField2 = 'SomeQueryResultField2';
const SomeQueryDataField2 = 'SomeQueryDataField2';
export const QUERY_CREATED_BY_GQL_FUNCTION_2 = gql`
  query ${SomeQueryName2} {
    ${SomeQueryResponseField2}: SomeDataQuery {
      ${SomeQueryResultField2} {
        ${SomeQueryDataField2} {
          someDataField {
            ...ExampleFragment
          }
          ...ExampleFragment2
        }
      }
    }
  }
  ${ExampleFragment}
  ${ExampleFragment2}
`;
// ** - example for no variables as fields used in a query
export const QUERY_CREATED_BY_GQL_FUNCTION_3 = gql`
  query SomeQueryName3 {
    response: SomeDataQuery {
      result {
        ...ExampleFragment2
      }
    }
  }
  ${ExampleFragment2}
`;
import queries and field names if exist
import { updateQueryHelper } from 'apollo-enchanted-cache-inmemory';
import {
    SomeQueryName,
    SomeQueryResponseField,
    SomeQueryResultField,
    SomeQueryName2,
    SomeQueryResultField2,
    SomeQueryResponseField2,
    SomeQueryDataField2,
    SomeQueryName3,
    QUERY_CREATED_BY_GQL_FUNCTION,
} from './queries';

/** @type SubscribedQueries */
const subscribedQueries = [
  // #1
  // each write into Apollo Cache with updating SomeQueryName
  // will cause storing SomeQueryName asynchronously
  {
    name: SomeQueryName,
    queryNode: QUERY_CREATED_BY_GQL_FUNCTION,
    storeName: SomeQueryName,
    nest: [SomeQueryResponseField], // optional
    // optional XOR - retriever
    retrieveField: SomeQueryResponseField,
    // or
    // optional XOR - retrieveField
    retriever: () => ({...}) // type Retriever
  },
  // #2
  // SomeQueryName2 will update SomeQueryName at SomeQueryResultField
  // with deep merging all nested objects as updateType='deepMerge';
  // data taken from
  // SomeQueryName2.SomeQueryName2.SomeQueryResponseField2.SomeQueryResultField2
  // is identical with SomeQueryName.SomeQueryResponseField.SomeQueryResultField
  // * - example for fields as variables used in a query
  {
    name: SomeQueryName2,
    queryNode: QUERY_CREATED_BY_GQL_FUNCTION,
    updateName: SomeQueryName,
    updater: (sourceQuery, targetQuery) => // type Retriever
      updateQueryHelper({
        sourceQuery,
        sourcePath: [SomeQueryResponseField2, SomeQueryResultField2, SomeQueryDataField2],
        targetQuery,
        targetPath: [SomeQueryResponseField, SomeQueryResultField],
        updateType: 'deepMerge',
      }),
  },
  // #3
  // SomeQueryName3 will update SomeQueryName at someDataField by replace
  // as updateType='replace' by default;
  // data taken from SomeQueryName3.response.result
  // is identical with SomeQueryName.SomeQueryResponseField.SomeQueryResultField
  // after updating SomeQueryName will be stored as tracked by #1 set
  // ** - example for no variables as fields used in a query
  {
    name: 'SomeQueryName3',
    queryNode: QUERY_CREATED_BY_GQL_FUNCTION,
    updateName: SomeQueryName2,
    updater: (sourceQuery, targetQuery) => // type Retriever
      updateQueryHelper({
        sourceQuery,
        sourcePath: ['response', 'result'],
        targetQuery,
        targetPath: ['SomeQueryResponseField', 'result', 'someDataField'],
        // updateType = 'replace' - by default
      }),
  },
];
// ...
export default subscribedQueries;

Basic usage:

Initiation:

import { InMemoryCache } from 'apollo-cache-inmemory';
import ApolloClient from 'apollo-client';
import { withClientState } from 'apollo-link-state';
import { ApolloLink } from 'apollo-link';
// if React Native
// up to RN v0.58
// import { AsyncStorage } from 'react-native';
// since RN v0.59
import AsyncStorage from '@react-native-community/async-storage';
// if Web just use window.LocalStorage

const inMemoryCache = new InMemoryCache({
  // ...
});
// ...
// for debug/log reasons
/** @type Logs */
const logs = {
  logCacheWrite: true,
  beforeHandlers: (cacheData, queryName) => {
    console.log('beforeHandlers', queryName, cacheData.data);
  },
  beforeWrite: (cacheData, queryName) => {
    console.log('beforeWrite', queryName, cacheData.data);
  },
  afterWrite: (cacheData, queryName) => {
    console.log('afterWrite', queryName, cacheData.data);
  },
};

const cache = createEnchantedInMemoryCache(
  inMemoryCache, // instance of `InMemoryCache`
  subscribedQueries, // config type `SubscribedQueries`
  AsyncStorage, // or `LocalStorage` - main app storage, can be omitted if `GraphQLStorage` provided  
  logs, // type Logs
  // GQLStorage, - alternative to `GraphQLStorage` class, e.g. `Realm` (mobile) / `IndexedDB` (web) Wrapper
);
const GQLStorage = cache.GQLStorage; // to get `GQLStorage`
const AppStorage = cache.AppStorage; // to get `AppStorage` - AsyncStorage or LocalStorage
// ...
const stateLink = withClientState({
  cache,
  resolvers,
  defaults,
});
// ...
const apolloClient = new ApolloClient({
  cache,
  link: ApolloLink.from([stateLink]),
});
// ...
export default apolloClient;

Restoring data from storage into cache:

// ...
(async () => {
  // ...
  await cache.restoreAllQueries();
  // ...
})();

API

SubscribedQuery

Array<SubscribedQuery>

| Prop | Type | Default | Note | | ------------------- | ------------ | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | name | string | (required) | query name which changes in Apollo cache will be tracked | | queryNode | Query | (required) | Graphql Query created by Apollo's gql utility; type DocumentNode from Apollo Client | | storeName | string | (semi-required)* | name used to store and restore in a storage formatted into 'Query:${storeName}' _* either storeName or updateName _ | | updateName | string | (semi-required)* | query name which will be updated _* either updateName or storeName _ | | nest | ObjectPath | | path to Query field for nesting restored data | | retrieveField** | string | (semi-required)* | path to Query field for _* in case if storeName provided _ ** - either retriever or retrieveField | | retriever** | Retriever | (semi-required)* | function returns data for storing/restoring _* in case if storeName provided _ ** - either retriever or retrieveField | | updater | Updater | (semi-required)* | function returns result with updated data for updating _* - in case if updateName provide |

updateQueryHelper: Updater

| Prop | Type | Default | Note | | --------------- | ----------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | sourceQuery | QueryObject | (required) | Object Data of source Query tracked for updating target Query | | sourcePath | ObjectPath | [] | path to Data source Query object field | | targetQuery | QueryObject | | Object Data of target Query should be updated | | targetPath | ObjectPath | [] | path to Data target Query object field | | updateType | UpdateTypesEnum | replace | replace - just replacing target Data at object some field by source Data rootMerge - merge target Data Object at object field by source Data with replacing tested Data deepMerge - merge target Object Data at all fields (sourcePath of sourceQuery) by source Object Data with same fields (targetPath of targetQuery); begins at source Object field and goes recursively into the depths | | sourceDefault | any | null | data to be used for updating the target Object if no present in the source Object |

Types

type ArrayPath = Array<string | number>; // ['a', 'b', 0, 'c', 1]

type ObjectPath = ArrayPath | string; // ['a', 'b', 'c', 0] | 'a.b.c.0'

type QueryObject<Data> = { Object; Data }; // Query result data

type Updater = <T1, T2, T3>(
  sourceQuery: QueryObject<T1>,
  targetQuery: QueryObject<T2>,
) => QueryObject<T3>;

type Retriever = <T1, T2, T3>(
  sourceQuery: QueryObject<T1>,
  targetQuery: QueryObject<T2>,
) => QueryObject<T3>;

type LinkedQuery = {
  name: string;
  queryNode: DocumentNode; // Apollo Query definition, returned by gql`...`
  updateName: string;
  updater: Updater;
};

type StoredQuery = {
  name: string;
  queryNode: DocumentNode; // Apollo Query definition, returned by gql`...`
  storeName: string;
  nest?: ObjectPath;
  retrieveField?: string;
  retriever?: Retriever;
};

type SubscribedQuery = LinkedQuery | StoredQuery;

type SubscribedQueries = Array<SubscribedQuery>;

type DepTrackingCache = { data: Object; depend: Object };

type Logger = (cacheData: DepTrackingCache, queryName: String) => void;

type Logs = {
    logCacheWrite: Boolean,
    beforeHandlers: Logger,
    beforeWrite: Logger,
    afterWrite: Logger,
};

enum UpdateTypesEnum {
  replace = 'replace',
  rootMerge = 'rootMerge',
  deepMerge = 'deepMerge',
}

License

Copyright (c) 2019 KosiakMD (Anton Kosiak)

Licensed under the The MIT License (MIT) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

https://raw.githubusercontent.com/airbnb/react-native-maps/master/LICENSE

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.