Source: api/shop/shopId.js

import { query } from 'cpb-datastore';
/**
 * @class module:cpb-api/ShopIdService
 * ### Provides methods for the retrieval of **shopID** and **shopName**
 * The storage directories are named after the **shopID**
 * While the **shopName** is being used elsewhere
 */
class ShopIdService {
  /**
   * shopID->shopName map
   * @private @static @type {Map<number, string>}
   */
  static #IDS = new Map();
  /**
   * shopName->shopID map
   * @private @static @type {Map<string, number>}
   */
  static #NAMES = new Map();

  //  static #NAMES_NOT_NULL = new Map();

  /**
   * get shopID's map
   * @return {Map<number,string>}
   */
  get ids() {
    return ShopIdService.#IDS;
  }

  /**
   * get shopName's map
   * @return {Map<string,number>} ShopIdService.#NAMES
   */
  get names() {
    return ShopIdService.#NAMES;
  }

  /**
   * load datastore data and populate maps
   * @return {Promise<ShopIdService>}
   * @static @async
   */
  static async #load() {
    const cpbTokens = process.env.CPB_TOKENS_KIND || 'custom-product-builder-production-tokens';
    const kinds = ['shopify_shops', cpbTokens, 'custom-product-builder-shops-stats'],
      order = 'shopName',
      selector = ['shopID', 'shopName'],
      groupBy = selector;

    for (const kind of kinds) {
      const querySettings = { kind, selector, groupBy, order },
        data = await query(querySettings).catch(console.error);

      for (const { shopID: id, shopName: name } of data) {
        if (id) {
          ShopIdService.#IDS.set(id, name);
          ShopIdService.#NAMES.set(name, id);
        }
        //        else console.warn(`[#load] NO_ID`);
      }
    }
    console.info(`[ShopIDService.load]: 
    #IDS: ${ShopIdService.#IDS.size}
     #NAMES: ${ShopIdService.#NAMES.size}`);

    return ShopIdService;
  }

  /**
   * check if the supplied value is number
   * @param {*} val
   * @return {boolean} isNumber
   */
  static isNumber(val) {
    return !isNaN(+val) && +val == val;
  }

  /**
   *  get shopName from its shopID
   * @param {!number|string} id - shopID
   * @param {?boolean|undefined} [fetch] - load data from datastore
   * @return {Promise<string|undefined|Map<number,string>>} name - shopName
   */
  static async #getName(id, fetch) {
    if (fetch || !ShopIdService.#IDS.size) await ShopIdService.load();
    if (!id) return ShopIdService.#IDS;
    return ShopIdService.#IDS.get(+id) || ShopIdService.#NAMES.get(id);
  }

  /**
   * get shopID from the shopName. If name is not given the entire map is returned
   * @param {string} name - shopName
   * @param {?boolean|undefined} [fetch] - fetch datastore data
   * @return {Promise<Map<string, number>|number|undefined>} shopID
   */
  static async #getId(name, fetch) {
    if (fetch || !ShopIdService.#NAMES.size) await ShopIdService.#load();
    if (!name) return ShopIdService.#NAMES;
    return ShopIdService.#NAMES.get(name);
  }

  /**
   * call to static load method from instance
   * @return {Promise<ShopIdService>}
   */
  async load() {
    await ShopIdService.#load();
    return this;
  }

  /**
   * call to static load method from instance
   * @param {string} name
   * @param fetch
   * @return {Promise<Map<string, number>|number|undefined>}
   */
  async getId(name, fetch) {
    return await ShopIdService.#getId(name, fetch);
  }

  /**
   * call to static load method from instance
   * @param {number} id
   * @param fetch
   * @return {Promise<string>} shopName
   */
  async getName(id, fetch) {
    return await ShopIdService.#getName(id, fetch);
  }

  /**
   * get <**shopID**, **shopName**> tuple from either **shopID** or **shopName**
   * @param {!number|string} idOrName
   * @param fetch
   * @return {{name: string, id: number}}
   */
  async getIdName(idOrName, fetch) {
    if (!idOrName) throw new TypeError('!idOrName');
    if (fetch) await this.load();
    let id, name;
    if (ShopIdService.isNumber(idOrName)) {
      id = idOrName;
      name = await ShopIdService.#getName(idOrName);
    } else {
      id = await ShopIdService.#getId(idOrName);
      name = idOrName;
    }
    if (!id) {
      console.error('[cpb-api/shop/ShopIdService][ERROR] missing id for ', { idOrName, id, name });
      name = null;
    }
    if (!name) {
      console.error('[cpb-api/shop/ShopIdService][ERROR] missing name for ', { idOrName, id, name });
      id = null;
    }

    return Promise.resolve({ id, name });
  }
}

/**
 * @exports module:cpb-api/shop/shopId
 * @type {ShopIdService}
 */
export const Service = new ShopIdService();
export default Service;