All files persistLink.js

88.89% Statements 24/27
88.89% Branches 16/18
83.33% Functions 10/12
95.65% Lines 22/23
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                        36x         1x 10x   10x 80x             17x   17x       17x                             81x                 10x 10x             6x           6x     6x     6x   59x 15x         6x 6x 6x     6x         1x      
import { visit } from 'graphql'
import { ApolloLink } from 'apollo-link'
import traverse from 'traverse'
 
import { extractPersistDirectivePaths, hasPersistDirective } from './transform'
 
/**
 * Given a data result object path, return the equivalent query selection path.
 *
 * @param {Array} path The data result object path. i.e.: ["a", 0, "b"]
 * @return {String} the query selection path. i.e.: "a.b"
 */
const toQueryPath = path => path.filter(key => isNaN(Number(key))).join('.')
 
/**
 * Given a data result object, attach __persist values.
 */
const attachPersists = (paths, object) => {
  const queryPaths = paths.map(toQueryPath)
 
  return traverse(object).map(function () {
    if (
      !this.isRoot &&
      this.node &&
      typeof this.node === 'object' &&
      Object.keys(this.node).length &&
      !Array.isArray(this.node)
    ) {
      const path = toQueryPath(this.path)
 
      this.update({
        __persist: Boolean(
          queryPaths.find(
            queryPath =>
              queryPath.indexOf(path) === 0 || path.indexOf(queryPath) === 0
          )
        ),
        ...this.node
      })
    }
  })
}
 
class PersistLink extends ApolloLink {
  /**
   * InStorageCache shouldPersist implementation for a __persist field validation.
   */
  static shouldPersist (op, dataId, data) {
    // console.log(dataId, data)
    return dataId === 'ROOT_QUERY' || (!data || !!data.__persist)
  }
 
  /**
   * InStorageCache addPersistField implementation to check for @perist directives.
   */
  static addPersistField = doc => hasPersistDirective(doc)
 
  constructor () {
    super()
    this.directive = 'persist'
  }
 
  /**
   * Link query requester.
   */
  request = (operation, forward) => {
    const { query, paths } = extractPersistDirectivePaths(
      operation.query,
      this.directive
    )
 
    // Early exit if no persist directive found.
    Iif (!paths.length) return forward(operation)
 
    // Replace query with one without @persist directives.
    operation.query = query
 
    // Remove requesting __persist fields.
    operation.query = visit(operation.query, {
      Field: ({ name: { value: name } }, key, parent, path, ancestors) => {
        if (name === '__persist') {
          return null
        }
      }
    })
 
    return forward(operation).map(result => {
      Eif (result.data) {
        result.data = attachPersists(paths, result.data)
      }
 
      return result
    })
  }
}
 
const createPersistLink = config => new PersistLink(config)
 
export { PersistLink, createPersistLink }