const { HttpStatusError } = require('common-errors');
const { FIELDS_TO_STRINGIFY, FILES_TAGS_FIELD } = require('../constant');
const safeParse = require('./safeParse');
const perf = require('ms-perf');
const handlePipelineError = require('./pipelineError');
const zipObject = require('lodash/zipObject');

const STRINGIFY_FIELDS = zipObject(FIELDS_TO_STRINGIFY);
const JSON_FIELDS = zipObject([FILES_TAGS_FIELD, 'files']);
const hasOwnProperty = Object.prototype.hasOwnProperty;

module.exports = function fetchData(key, omitFields = []) {
  const { redis } = this;
  const timer = perf('fetchData');

  return redis
    .pipeline()
    .exists(key)
    .hgetall(key)
    .exec()
    .tap(timer('redis'))
    .then(handlePipelineError)
    .tap(timer('handleError'))
    .spread((fileExists, data) => {
      if (!fileExists) {
        throw new HttpStatusError(404, 'could not find associated data');
      }

      const output = {};
      const fields = Object.keys(data);

      fields.forEach((field) => {
        if (omitFields.indexOf(field) >= 0) {
          return;
        }

        const value = data[field];
        if (hasOwnProperty.call(JSON_FIELDS, field)) {
          output[field] = safeParse(value, []);
        } else if (hasOwnProperty.call(STRINGIFY_FIELDS, field)) {
          output[field] = safeParse(value);
        } else {
          output[field] = value;
        }
      });

      return output;
    })
    .tap(timer('remapping'))
    .finally(timer);
};

@@ -300,16 +300,44 @@
 ect');%0A%0A
+/**%0A * Helper constants%0A */%0A
 const ST
@@ -502,16 +502,878 @@
 perty;%0A%0A
+/**%0A * Remaps & json-parses some of the fields%0A */%0Afunction remapData(field) %7B%0A  if (this.omitFields.indexOf(field) %3E= 0) %7B%0A    return;%0A  %7D%0A%0A  const value = this.data%5Bfield%5D;%0A  if (hasOwnProperty.call(JSON_FIELDS, field)) %7B%0A    this.output%5Bfield%5D = safeParse(value, %5B%5D);%0A  %7D else if (hasOwnProperty.call(STRINGIFY_FIELDS, field)) %7B%0A    this.output%5Bfield%5D = safeParse(value);%0A  %7D else %7B%0A    this.output%5Bfield%5D = value;%0A  %7D%0A%7D%0A%0A/**%0A * Checks error & remaps data%0A */%0Afunction reserializeData(fileExists, data) %7B%0A  if (!fileExists) %7B%0A    throw new HttpStatusError(404, 'could not find associated data');%0A  %7D%0A%0A  const output = %7B%7D;%0A  const fields = Object.keys(data);%0A  const ctx = %7B output, data, omitFields: this.omitFields %7D;%0A%0A  fields.forEach(remapData, ctx);%0A%0A  return output;%0A%7D%0A%0A/**%0A * Fetches data%0A * @param  %7BString%7D key%0A * @param  %7BArray%7D  %5BomitFields=%5B%5D%5D%0A */%0A
 module.e
@@ -1471,17 +1471,17 @@
  = perf(
-'
+%60
 fetchDat
@@ -1481,17 +1481,24 @@
 etchData
-'
+:$%7Bkey%7D%60
 );%0A%0A  re
@@ -1667,668 +1667,56 @@
    .
-spread((fileExists, data) =%3E %7B%0A      if (!fileExists) %7B%0A        throw new HttpStatusError(404, 'could not find associated data');%0A      %7D%0A%0A      const output = %7B%7D;%0A      const fields = Object.keys(data);%0A%0A      fields.forEach((field) =%3E %7B%0A        if (omitFields.indexOf(field) %3E= 0) %7B%0A          return;%0A        %7D%0A%0A        const value = data%5Bfield%5D;%0A        if (hasOwnProperty.call(JSON_FIELDS, field)) %7B%0A          output%5Bfield%5D = safeParse(value, %5B%5D);%0A        %7D else if (hasOwnProperty.call(STRINGIFY_FIELDS, field)) %7B%0A          output%5Bfield%5D = safeParse(value);%0A        %7D else %7B%0A          output%5Bfield%5D = value;%0A        %7D%0A      %7D);%0A%0A      return output;%0A    %7D
+bind(%7B omitFields %7D)%0A    .spread(reserializeData
 )%0A  

optimize partial functions on fetchData