/**
* @class module:cpb-api/product/ProductIdService
* ### Provides methods for the retrieval of both **productID** and **productHandle** from either value
*
* While the **shopName** is being used elsewhere
*/
import { query } from 'cpb-datastore';
class ProductIdService {
static #settings = {
kinds: ['shopify_products'],
};
static #cache = new Map();
state = {};
/**
* shopID->shopName map
* @private @static @type {Map<number, string>}
*/
static #IDS = new Map();
/**
* shopName->shopID map
* @private @static @type {Map<string, number>}
*/
static #HANDLES = new Map();
/**
* get shopID's map
* @return {Map<number,string>}
*/
get ids() {
return ProductIdService.#IDS;
}
/**
* get shopName's map
* @return {Map<string,number>} ProductIdService.#HANDLES
*/
get handles() {
return ProductIdService.#HANDLES;
}
/**
* load datastore data and populate maps
* @return {Promise<ProductIdService>}
* @static @async
*/
static async #load(filter) {
const order = 'handle',
selector = ['id', 'handle', 'shopName', 'shopID'];
for (const kind of ProductIdService.#settings.kinds) {
const querySettings = { kind, filter, order },
data = await query(querySettings).catch(console.error);
for (const { id, handle } of data) {
ProductIdService.#IDS.set(+id, handle);
ProductIdService.#HANDLES.set(handle, +id);
}
}
console.info(`[ProductIdService.load]:
#IDS: ${ProductIdService.#IDS.size}
#HANDLES: ${ProductIdService.#HANDLES.size}`);
return ProductIdService;
}
/**
* 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 #getHandle(id, fetch) {
if (fetch || !ProductIdService.#IDS.size) await ProductIdService.#load();
if (!id) return ProductIdService.#IDS;
return ProductIdService.#IDS.get(+id); // || ProductIdService.#HANDLES.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 || !ProductIdService.#HANDLES.size) await ProductIdService.#load();
if (!name) return ProductIdService.#HANDLES;
return ProductIdService.#HANDLES.get(name);
}
/**
* call to static load method from instance
* @return {Promise<ProductIdService>}
*/
async load(filter = {}) {
await ProductIdService.#load(filter);
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 ProductIdService.#getId(name, fetch);
}
/**
* call to static load method from instance
* @param {number} id
* @param fetch
* @return {Promise<string>} shopName
*/
async getHandle(id, fetch) {
return await ProductIdService.#getHandle(id, fetch);
}
/**
* get <**productID**, **productHandle**> tuple from either **productID** or **productHandle**
* @param {!number|string} idOrName
* @param shop
* @param fetch
* @return {{name: string, id: number}}
*/
async getIdHandle(idOrName, { shopID, shopName } = {}, fetch) {
if (!idOrName) throw new TypeError('!idOrName');
if (!shopName && !shopID) throw new TypeError('!shopName||!shopID');
// if (fetch) await this.load();
let id, handle;
if (ProductIdService.isNumber(idOrName) && idOrName.length > 6) {
id = idOrName;
handle = await ProductIdService.#getHandle(idOrName);
} else {
id = await ProductIdService.#getId(idOrName);
handle = idOrName;
}
if (!id) {
console.error('[cpb-api/product/ProductIdService][ERROR] missing id for ', { idOrName, id, handle });
handle = null;
}
if (!handle) {
console.error('[cpb-api/product/ProductIdService][ERROR] missing name for ', { idOrName, id, handle });
id = null;
}
return Promise.resolve({ id, handle });
}
}
export default new ProductIdService();