import { addJob, JobKind } from '@spokenio/jobqueue-producer'; import { subHours } from 'date-fns'; import express, { Express, Request } from 'express'; import { getRepository, In, IsNull, LessThan } from 'typeorm'; import logger from '@/logger'; import { batchProcessEntityStream } from '@/entities/utils'; import { Product } from '@/entities'; const setup = (): Express => { const app = express(); app.put('/update', async (req: Request<{ force?: string }>, res) => { const forceQuery = req.query.force; if (forceQuery && typeof forceQuery !== 'string') { return res .status(400) .send("Query param 'force' has to be of type string"); } const forceAsString = forceQuery?.toLowerCase().trim(); const force = forceAsString && forceAsString !== 'false' && forceAsString !== '0'; batchProcessEntityStream( Product, async (products) => { logger.info( `Queuing bulk update google shopping offers price for ${products.length} products.` ); const googleShoppingIDsOfProduct = products.map( ({ googleShoppingIDs }) => googleShoppingIDs ); await Promise.all( googleShoppingIDsOfProduct.map(async (googleShoppingIDs) => { if (googleShoppingIDs?.length) { await addJob(JobKind.UPDATE_GOOGLE_SHOPPING_OFFERS_PRICE_1, { googleShoppingIDs: googleShoppingIDs, }); } }) ); await getRepository(Product).update( { id: In(products.map(({ id }) => id)) }, { lastScrapedAt: new Date(), } ); }, { where: force ? {} : [ { lastScrapedAt: LessThan(subHours(new Date(), 23)), }, { lastScrapedAt: IsNull(), }, ], } ); return res.status(200).json({ status: 'queued', }); }); return app; }; export default setup;