All files / platform/packages/partial-response/src/Bumblebee PartialFieldManager.js

97.06% Statements 33/34
92% Branches 23/25
100% Functions 10/10
96.97% Lines 32/33

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    1x 1x   1x                 420x             513x             392x                   225x 700x     225x 225x 202x     23x 143x   23x                 288x                   225x               225x                   143x       143x   143x   143x 44x   99x   86x 16x         70x       8x     62x 18x     44x   57x       1x  
'use strict';
 
const _ = require('lodash');
const jsonMask = require('json-mask');
 
const WILDCARD_CHAR = '*';
 
class PartialFieldManager {
  /**
   *
   * @param {string | undefined} partialFieldsString
   */
  constructor(partialFieldsString = null) {
    // Init partial fields is wildcard
    this._partialFieldsString = partialFieldsString || WILDCARD_CHAR;
  }
 
  /**
   * @returns {string}
   */
  getPartialFieldsString() {
    return this._partialFieldsString || WILDCARD_CHAR;
  }
 
  /**
   * @param {string} partialFieldsString
   */
  setPartialFieldsString(partialFieldsString) {
    this._partialFieldsString = partialFieldsString || WILDCARD_CHAR;
  }
 
  /**
   * Reduce the includes depends on partial fields (X-Fields header).
   * Not include the resources that not included in partial fields
   * @param {Array|string} includes
   * @returns Array
   */
  reduceIncludes(includes) {
    if (typeof includes === 'string') {
      includes = includes.split(',').map((item) => item.trim());
    }
 
    const parsedPartialFields = this._parsePartialFields(this.getPartialFieldsString());
    if (!parsedPartialFields || this._isIncludeAllFields(parsedPartialFields)) {
      return includes;
    }
 
    const reducedIncludes = includes.filter((include) =>
      this._isIncludedField(include, parsedPartialFields),
    );
    return reducedIncludes;
  }
 
  /**
   * Return filtered data
   * @param {*} data
   * @returns
   */
  toJSON(data) {
    return jsonMask(data, this.getPartialFieldsString());
  }
 
  /**
   * Check include all fields
   * @param {Object} parsedProperties
   * @returns
   */
  _isIncludeAllFields(parsedProperties) {
    // When there is wildcard on first level, it is required all fields
    return _.has(parsedProperties, WILDCARD_CHAR);
  }
 
  /**
   * @param {string} partialFieldsString
   * @returns {Record<string, string>|null}
   */
  _parsePartialFields(partialFieldsString) {
    return jsonMask.compile(partialFieldsString);
  }
 
  /**
   * Check the include is required in partial fields
   * @param {string} include
   * @param {Record<string, string>} parsedPartialFields
   * @returns
   */
  _isIncludedField(include, parsedPartialFields) {
    Iif (_.has(parsedPartialFields, WILDCARD_CHAR)) {
      return true;
    }
 
    const nested = include.split('.');
    // Take the first level
    let path = nested.shift();
    // Return since it does not exist in partial fields
    if (!_.has(parsedPartialFields, path)) {
      return false;
    }
    for (const subPart of nested) {
      // wildcard will return all sub-parts
      if (_.has(parsedPartialFields, `${path}.properties.${WILDCARD_CHAR}`)) {
        return true;
      }
      // When partial fields contain only root path, take all sub-parts
      // When mask: (order) => parsedPartialFields = {order: {type: "object"}}:
      //    Should take all includes [order.staff, order]
      if (
        _.has(parsedPartialFields, `${path}`) &&
        !_.has(parsedPartialFields, `${path}.properties`)
      ) {
        return true;
      }
      // Return false if subpart does not exist in properties list
      if (!_.has(parsedPartialFields, `${path}.properties.${subPart}`)) {
        return false;
      }
      // Continue next deeper path
      path = `${path}.properties.${subPart}`;
    }
    return true;
  }
}
 
module.exports = PartialFieldManager;