Repository URL to install this package:
|
Version:
9.0.35-framework ▾
|
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// tslint:disable:adjacent-overload-signatures
const perf_hooks_1 = require("perf_hooks");
const fs_1 = require("fs");
const path_1 = require("path");
const exotic_1 = require("exotic");
const graphql_toolset_1 = require("@skava/graphql-toolset");
const log_1 = require("../../log");
const bindings_1 = require("../catalog/bindings");
const bindings_2 = require("../categories/bindings");
const index_1 = require("../index");
const cache_1 = require("../../cache");
const cache = new Map();
cache.set('categories', []);
cache.set('productList', new Map());
cache.set('productDetail', new Map());
cache.set('catalogLite', new Map());
const scoped = {
requestCache: undefined,
appBindings: undefined,
};
function create() {
scoped.requestCache = cache_1.toCache();
// @todo fix typings in @skava/graphql-toolset
scoped.appBindings = graphql_toolset_1.toGraphqlModuleTest({
graphqlModule: index_1.AppModules,
options: {
cache: scoped.requestCache,
},
});
}
async function mapCategories(categories = exotic_1.EMPTY_ARRAY) {
console.log('___mapCategories___', categories);
const catalogBindings = await bindings_1.toCatalogHelpers(scoped.appBindings);
/**
* @todo return and flatmap all promises to send all at once...
*/
const allThesePromises = categories.map((category = { identifier: '@@EMPTY_CATEGORY' }) => new Promise(async (done) => {
/**
* @todo put catalogFull + catalogLite => same array as pages
*/
console.log(`getting category ${category.name}`);
if (cache.get('productList').has(category.identifier)) {
console.log(`[sponge]{productList} already had ${category.identifier}`);
done();
return;
}
const catalogResponse = await catalogBindings.getProductList({
categoryId: category.identifier,
limit: 50,
});
const { productList } = catalogResponse.data;
cache.get('productList').set(productList.identifier, productList);
// @todo validate
const products = productList.products || [];
/**
* @todo remove errors with `Sorry , no results found! Please check the spelling or try searching for something else`
* @todo split into fn
*/
const pagination = Object.assign({}, productList.pagination, { limit: 50 });
console.log('___PAGINATION___', { offset: pagination.offset, totalPages: pagination.totalPages }, +pagination.totalPages > +pagination.offset);
const pages = [];
/**
* @todo I think this is not working when we *get* from the cache
* it does not include `page=`
*/
while (+pagination.totalPages > +pagination.offset) {
console.log(`getting next page for ${productList.identifier} ${pagination.offset} totalPages: ${pagination.totalPages}`);
pagination.offset += 1;
const offset = pagination.offset;
pages.push(new Promise(async (donePage) => {
try {
const productListPaginatedKey = productList.identifier + `offset=${offset}`;
if (cache.get('productList').has(productListPaginatedKey)) {
console.log(`[sponge]{plp} already had ${productListPaginatedKey}`);
donePage();
return;
}
const nextCatalogResponse = await catalogBindings.getProductList({
categoryId: category.identifier,
offset,
limit: pagination.limit,
});
const nextProductList = nextCatalogResponse.data.productList;
pagination.hasNextPage = nextProductList.pagination.hasNextPage;
products.push(...nextProductList.products);
cache
.get('productList')
.set(productListPaginatedKey, nextProductList);
donePage();
}
catch (exception) {
console.error(exception);
}
}));
}
// all pages, at ~ same time
await Promise.all(pages);
// @todo, final step would be to query all selected facets o.o
const catalogLiteResponse = await catalogBindings.getCatalogLite({
categoryId: category.identifier,
});
const { catalogLite } = catalogLiteResponse.data;
cache.get('catalogLite').set(category.identifier, catalogLite);
const andTheyAllFeelSoWastedOnMyself = products.map(async (productListProduct) => {
if (cache.get('productDetail').has(productListProduct.identifier)) {
console.log(`[sponge]{product} already had ${productListProduct.identifier}`);
return Promise.resolve();
}
const productDetailResponse = await catalogBindings.getProductDetail({
productId: productListProduct.identifier,
});
const product = productDetailResponse.data.productDetail;
cache.get('productDetail').set(product.identifier, product);
return Promise.resolve();
});
console.log('waiting for products');
await Promise.all(andTheyAllFeelSoWastedOnMyself);
console.log('done waiting for products');
if (exotic_1.isNonEmptyArray(category.categories)) {
await mapCategories(category.categories);
done();
}
else {
done();
return Promise.resolve();
}
}));
// @todo return?
await Promise.all(allThesePromises);
}
async function getCategories() {
const categoriesBinding = await bindings_2.toCategoriesHelpers(scoped.appBindings);
const response = await categoriesBinding.getCategories();
const categories = response.data.categories;
cache.set('categories', categories);
return categories;
}
function fromCacheToSerialized(cacheArg) {
return {
categories: cacheArg.get('categories'),
productList: exotic_1.fromMapToObj(cacheArg.get('productList')),
productDetail: exotic_1.fromMapToObj(cacheArg.get('productDetail')),
catalogLite: exotic_1.fromMapToObj(cacheArg.get('catalogLite')),
};
}
class Timer {
constructor() {
this.store = new Map();
}
start() {
const now = perf_hooks_1.performance.now();
this.store.set('start', now);
return this;
}
end() {
const now = perf_hooks_1.performance.now();
this.store.set('end', now);
return this;
}
log() {
const start = this.store.get('start');
const end = this.store.get('end');
const duration = end - start;
log_1.logger.info('[sponge] time: ' + duration);
return this;
}
}
function logCache() {
const cacheAsObj = fromCacheToSerialized(cache);
console.log('\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n');
console.log(cacheAsObj);
}
const redis_1 = require("../../cache/redis");
async function writeToRedis() {
const cacheAsObj = fromCacheToSerialized(cache);
await Promise.all([
...Object.keys(cacheAsObj).map(key => redis_1.set(key, cacheAsObj[key])),
...Object.keys(cacheAsObj.productList).map(key => redis_1.set('productList.' + key, cacheAsObj.productList[key])),
...Object.keys(cacheAsObj.catalogLite).map(key => redis_1.set('catalogLite.' + key, cacheAsObj.catalogLite[key])),
...Object.keys(cacheAsObj.productDetail).map(key => redis_1.set('productDetail.' + key, cacheAsObj.productDetail[key])),
]);
}
async function persist() {
if (process.env.CACHE_TYPE === 'redis') {
await writeToRedis();
}
else {
fs_1.writeFileSync(path_1.resolve(__dirname, './sponge.json'), JSON.stringify(cacheAsObj, undefined, 2));
}
}
async function soakSponge() {
create();
await scoped.requestCache.rehydrate();
const timer = new Timer().start();
const categories = await getCategories();
await mapCategories(categories);
timer.end().log();
persist();
}
exports.soakSponge = soakSponge;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9ncmFwaHFsLW1vZHVsZXMvc3BvbmdlL2RlcHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSw4Q0FBOEM7QUFDOUMsMkNBQXdDO0FBQ3hDLDJCQUFrQztBQUNsQywrQkFBOEI7QUFDOUIsbUNBQW1FO0FBQ25FLDREQUE2RTtBQUM3RSxtQ0FBa0M7QUFDbEMsa0RBQXNEO0FBTXRELHFEQUE0RDtBQU01RCxvQ0FBcUM7QUFDckMsdUNBQXFDO0FBbUJyQyxNQUFNLEtBQUssR0FBZ0IsSUFBSSxHQUFHLEVBQUUsQ0FBQTtBQUNwQyxLQUFLLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQTtBQUMzQixLQUFLLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUE7QUFDbkMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxlQUFlLEVBQUUsSUFBSSxHQUFHLEVBQUUsQ0FBQyxDQUFBO0FBQ3JDLEtBQUssQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLElBQUksR0FBRyxFQUFFLENBQUMsQ0FBQTtBQUVuQyxNQUFNLE1BQU0sR0FHUjtJQUNGLFlBQVksRUFBRSxTQUFTO0lBQ3ZCLFdBQVcsRUFBRSxTQUFTO0NBQ3ZCLENBQUE7QUFDRCxTQUFTLE1BQU07SUFDYixNQUFNLENBQUMsWUFBWSxHQUFHLGVBQU8sRUFBRSxDQUFBO0lBQy9CLDhDQUE4QztJQUM5QyxNQUFNLENBQUMsV0FBVyxHQUFHLHFDQUFtQixDQUFDO1FBQ3ZDLGFBQWEsRUFBRSxrQkFBVTtRQUN6QixPQUFPLEVBQUU7WUFDUCxLQUFLLEVBQUUsTUFBTSxDQUFDLFlBQVk7U0FDM0I7S0FDRixDQUFDLENBQUE7QUFDSixDQUFDO0FBRUQsS0FBSyxVQUFVLGFBQWEsQ0FDMUIsYUFBK0Isb0JBQWtCO0lBRWpELE9BQU8sQ0FBQyxHQUFHLENBQUMscUJBQXFCLEVB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