Source: store/introspector.js

import { isEqual } from "lodash";

import Client from "../lib/GraphClient/GraphClient.js";
import introspectionQuery from "../lib/GraphClient/queries/introspection.json";

let client = new Client();
export const mutations = {
  setParameters(state, data) {
    try {
      if (Object.keys(data).includes("errors")) {
        state.error = data.errors[0].message;
      } else {
        localStorage.introspectionQuery = JSON.stringify(data);
        let queryParams = data.data["__schema"]["types"].filter(
          (param) => param.name === "Query",
        )[0];
        state.searchQueryParameters = queryParams.fields.filter(
          (param) => param.name === "searchFairsharingRecords",
        )[0];
        if (!localStorage.searchQueryParameters) {
          localStorage.searchQueryParameters = JSON.stringify(
            state.searchQueryParameters,
          );
        } else {
          if (
            !isEqual(
              JSON.parse(localStorage.searchQueryParameters),
              JSON.parse(JSON.stringify(state.searchQueryParameters)),
            )
          ) {
            localStorage.searchQueryParameters = JSON.stringify(
              state.searchQueryParameters,
            );
          } else {
            state.searchQueryParameters = JSON.parse(
              localStorage.searchQueryParameters,
            );
          }
        }
      }
    } catch (e) {
      state.error = "Can't initialize application";
    }
  },
  setLocalStorageExpiryTime: function () {
    let now = new Date();
    localStorage.expiryDate = now;
    return now;
  },
  setMaintenanceMode(state) {
    state.maintenanceMode = true;
  },
  setReadOnlyMode(state) {
    state.readOnlyMode = true;
  },
};

export const actions = {
  async fetchParameters(state, timer) {
    let expirationTimer = timer ? timer : 24;
    let data = await client.getData(introspectionQuery);
    if (localStorage.expiryDate) {
      const expiration = paramsAreExpired(
        localStorage.expiryDate,
        expirationTimer,
      );
      if (expiration) {
        this.commit("introspection/setLocalStorageExpiryTime");
        this.commit("introspection/setParameters", data.data);
      } else {
        this.commit(
          "introspection/setParameters",
          JSON.parse(localStorage.introspectionQuery),
        );
      }
    }
    if (!localStorage.introspectionQuery) {
      this.commit("introspection/setLocalStorageExpiryTime");
      this.commit("introspection/setParameters", data.data);
    }
    if (data.headers["maintenance"] === "true")
      this.commit("introspection/setMaintenanceMode");
    if (data.headers["read-only"] === "true")
      this.commit("introspection/setReadOnlyMode");
    // temp!
    // this.commit("introspection/setMaintenanceMode");
    // this.commit("introspection/setReadOnlyMode");
  },
};
export const getters = {
  buildQueryParameters: (state) => (params) => {
    let queryParameters = {};
    Object.keys(params[1]).forEach(function (param) {
      let expectedTypeObject = null;
      if (state.searchQueryParameters.args === undefined) return;
      let currentParam = state.searchQueryParameters.args.filter(
        (arg) => arg.name === param,
      )[0];
      if (currentParam === undefined) return;
      expectedTypeObject = currentParam.type;
      if (expectedTypeObject.kind !== "LIST") {
        queryParameters[param] = parseParam(
          expectedTypeObject,
          params[1][param],
        );
      } else {
        const currentVal = params[1][param];
        const expectedType = expectedTypeObject["ofType"]["ofType"].name;
        queryParameters[param] = [];
        if (currentVal.indexOf(",") > 0) {
          currentVal.split(",").forEach(function (val) {
            queryParameters[param].push(
              decodeURIComponent(parseParam(expectedType, val)),
            );
          });
        } else {
          queryParameters[param] = decodeURIComponent(
            parseParam(expectedType, currentVal),
          );
        }
      }
    });
    return queryParameters;
  },
};

/**
 * The introspection store is related to the introspection query that let us know which fields/types are allowed by the searchFairsharingRecords query
 * @type {Object}
 * */
let introspectionStore = {
  namespaced: true,
  /**
   * @name states
   * @type {Object}
   * @property {String} errors - collects errors while introspecting.
   * @property {object} searchQueryParameters -  filters query parameters object coming from API.
   */
  state: {
    errors: String,
    searchQueryParameters: {},
    maintenanceMode: false,
    readOnlyMode: false,
  },
  modules: {},
  mutations: mutations,
  actions: actions,
  getters: getters,
};
export default introspectionStore;

/**
 * Given a type and a value, parse the value with the expected type.
 * @param {Object} param - the parameter types allowed
 * @param {String} paramVal -  the value to be parsed
 * @returns {String | Number | Boolean} paramVal - the parse value
 * @example <caption> Example usage of parseParam </caption>
 *  parseParam({name: "Boolean"}, "true");
 *  // return True
 */
const parseParam = function (param, paramVal) {
  if (param.name === "Int") {
    return parseFloat(paramVal);
  } else if (param.name === "Boolean") {
    return JSON.parse(paramVal);
  }
  return paramVal;
};

/**
 * Compares the given date with now and returns true if it greater than the given timer
 * @param {Date} expiryDate - the date to compare
 * @param {Number} expirationTimer - the timer to determine if the date has been expired or not
 * @returns {boolean} - is the data expired or not
 */
export const paramsAreExpired = function (expiryDate, expirationTimer) {
  const limit = expirationTimer * 3600;
  const expiration = new Date(expiryDate);
  const now = new Date();
  return now - expiration - limit >= 0;
};