All files / latest/src/handlers/get getAll.js

100% Statements 169/169
100% Branches 35/35
100% Functions 11/11
100% Lines 169/169

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 1701x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 105x 5x 3x 3x 2x 2x 100x 100x 1x 1x 1x 1x 1x 105x 74x 74x 74x 31x 31x 1x 1x 1x 1x 1x 43x 9x 9x 43x 43x 1x 1x 1x 1x 1x 3x 3x 3x 11x 11x 11x 11x 11x 11x 3x 3x 1x 1x 1x 1x 1x 22x 66x 66x 66x 66x 66x 22x 1x 1x 1x 1x 1x 105x 105x 25x 25x 3x 3x 3x 25x 22x 22x 25x 105x 105x 1x 1x 1x 1x 1x 105x 74x 74x 31x 31x 1x 1x 1x 1x 1x 8x 4x 4x 4x 4x 1x 1x 1x 1x 1x 43x 43x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 60x 60x 5x 5x 55x 60x 8x 8x 43x 43x 43x 43x 105x 105x 43x 43x 43x 43x 105x 62x 62x 62x 62x 62x 105x 105x 105x 105x 105x 105x 105x 43x 43x 43x 43x 1x 1x  
const JG = require('../../../index.js');
 
const pathTransformer = require('../../helpers/pathTransformer');
const stringify = require('../basic/stringify');
const getMultiplePathElements = require('../../helpers/pathElements/getMultiple');
const doesPathIndicateComplexity = require('./src/doesPathIndicateComplexity');
const simpleGet = require('./src/simpleGet');
const validateOutput = require('./src/validateOutput');
const getAllKeysFromObject = require('../../helpers/pathElements/getKeys/getAllKeysFromObject');
const getAllKeysFromArray = require('../../helpers/pathElements/getKeys/getAllKeysFromArray');
 
const getCache = {};
 
/**
 * Get names of elements either from wildcard or from other type of elements
 */
const getPathElements = (element, obj, tempObject, getType, priorPath) => {
  if (element.wildcard) {
    if (getType === 'number') {
      return getAllKeysFromArray(tempObject);
    }
    return getAllKeysFromObject(tempObject);
  }
  return getMultiplePathElements(element, obj, tempObject, getType, priorPath);
};
 
/**
 * If there is only one result, update tempObject
 */
const setTempObjectNewIteration = (elementValues, tempObject, getType) => {
  if (elementValues.length === 1) {
    const toReturn = tempObject[elementValues[0][getType]];
    return toReturn;
  }
  return undefined;
};
 
/**
 * If there is a remaining tempObject, add it to results.
 */
const addFinalTempToResults = (results, tempObject) => {
  if (tempObject !== undefined) {
    results.push(tempObject);
  }
  return results;
};
 
/**
 * Get all results that need to be retreived with getAll
 */
const addMultipleResults = (arrayPath, index, elementValues, remainingPath, obj, results) => {
  let newResults = results;
  const previousPath = arrayPath.slice(0, index);
  elementValues.forEach((elementValue) => {
    const checkPath = [
      ...previousPath, elementValue, ...remainingPath,
    ];
    const r = new JG.Json(obj).getAll(checkPath);
    newResults = [...newResults, ...r];
  });
  return newResults;
};
 
/**
 * Get all results that can be retreived with get function
 */
const addSingleResults = (elementValues, tempObject, remainingPath, newResults) => {
  elementValues.forEach((elementValue) => {
    const singleResult = simpleGet(tempObject, [elementValue, ...remainingPath]);
    if (singleResult !== undefined) {
      newResults.push(singleResult);
    }
  });
};
 
/**
 * When multiple elementValues are found, attempt to get them all and store in results
 */
const addToResults = (results, elementValues, index, obj, arrayPath, tempObject) => {
  let newResults = results;
  if (elementValues.length > 1) {
    const remainingPath = arrayPath.slice(index + 1);
    if (doesPathIndicateComplexity(remainingPath)) {
      newResults = addMultipleResults(
        arrayPath, index, elementValues, remainingPath, obj, newResults,
      );
    } else {
      addSingleResults(elementValues, tempObject, remainingPath, newResults);
    }
  }
  return newResults;
};
 
/**
 * Update arrayPath with resolved element
 */
const setArrayPathIndex = (elementValues, currentPath) => {
  if (elementValues.length === 1 && typeof elementValues[0] === 'object') {
    return elementValues[0];
  }
  return currentPath;
};
 
/**
 * Returns an array with element, or empty array if element is undefined
 */
const returnArray = (element) => {
  if (element !== undefined) {
    return [element];
  }
  return [];
};
 
/**
 * Store result into cache so that it can be reused
 */
const setCache = (stringifiedPath, obj, tempObject) => {
  getCache[stringifiedPath] = { object: obj, result: tempObject };
};
 
/**
 * Validate if cache is for the right object
 */
const validateCache = (cache, obj) => cache && cache.object === obj;
 
/**
 * Retreives all values from objects specified path
 * @param {Object} obj - object/array from which value should be retreived.
 * @param {any} path - string or array representation of path to set.
 * @returns {Array} returns array of values that match the specified path with logical checks
 */
const getAll = (obj, path) => {
  const stringifiedPath = stringify(path);
  if (validateCache(getCache[stringifiedPath], obj)) {
    return getCache[stringifiedPath].result;
  }
  const arrayPath = pathTransformer(path);
  if (!doesPathIndicateComplexity(arrayPath)) {
    return returnArray(simpleGet(obj, arrayPath));
  }
  const priorPath = [];
  let results = [];
  let tempObject = obj;
  arrayPath.every((singleElement, index) => {
    const element = (singleElement);
    if (Array.isArray(tempObject)) {
      const elementValues = getPathElements(element, obj, tempObject, 'number', priorPath);
      results = addToResults(results, elementValues, index, obj, arrayPath, tempObject);
      tempObject = setTempObjectNewIteration(elementValues, tempObject, 'number');
      arrayPath[index] = setArrayPathIndex(elementValues, arrayPath[index]);
    } else {
      const elementValues = getPathElements(element, obj, tempObject, 'string', priorPath);
      results = addToResults(results, elementValues, index, obj, arrayPath, tempObject);
      tempObject = setTempObjectNewIteration(elementValues, tempObject, 'string');
      arrayPath[index] = setArrayPathIndex(elementValues, arrayPath[index]);
    }
    priorPath.push(arrayPath[index]);
    const {
      shouldItContinue, newTempObject,
    } = validateOutput(tempObject, arrayPath.length - 1 === index);
    tempObject = newTempObject;
    return shouldItContinue;
  });
  results = addFinalTempToResults(results, tempObject);
  setCache(stringifiedPath, obj, results);
  return results;
};
 
module.exports = getAll;