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;