feat: Implement deals repository and routes for fetching best watched item prices
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Has been cancelled
- Added a new DealsRepository class to interact with the database for fetching the best sale prices of watched items. - Created a new route `/api/users/deals/best-watched-prices` to handle requests for the best prices of items the authenticated user is watching. - Enhanced logging in the FlyerDataTransformer and FlyerProcessingService for better traceability. - Updated tests to ensure proper logging and functionality in the FlyerProcessingService. - Refactored logger client to support structured logging for better consistency across the application.
This commit is contained in:
61
src/services/db/deals.db.ts
Normal file
61
src/services/db/deals.db.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
// src/services/db/deals.repository.ts
|
||||
import { getPool } from './connection.db';
|
||||
import { WatchedItemDeal } from '../../types';
|
||||
import { Pool } from 'pg';
|
||||
|
||||
export class DealsRepository {
|
||||
private pool: Pool;
|
||||
|
||||
constructor() {
|
||||
this.pool = getPool();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the best current sale price for each of a user's watched items.
|
||||
*
|
||||
* @param userId - The ID of the user whose watched items are being checked.
|
||||
* @returns A promise that resolves to an array of WatchedItemDeal objects.
|
||||
*/
|
||||
async findBestPricesForWatchedItems(userId: string): Promise<WatchedItemDeal[]> {
|
||||
const query = `
|
||||
WITH UserWatchedItems AS (
|
||||
-- Select all items the user is watching
|
||||
SELECT master_item_id FROM watched_items WHERE user_id = $1
|
||||
),
|
||||
RankedPrices AS (
|
||||
-- Find all current sale prices for those items and rank them
|
||||
SELECT
|
||||
fi.master_item_id,
|
||||
mgi.name AS item_name,
|
||||
fi.price_in_cents,
|
||||
s.name AS store_name,
|
||||
f.flyer_id,
|
||||
f.valid_to,
|
||||
ROW_NUMBER() OVER(PARTITION BY fi.master_item_id ORDER BY fi.price_in_cents ASC, f.valid_to DESC) as rn
|
||||
FROM flyer_items fi
|
||||
JOIN flyers f ON fi.flyer_id = f.flyer_id
|
||||
JOIN stores s ON f.store_id = s.store_id
|
||||
JOIN master_grocery_items mgi ON fi.master_item_id = mgi.master_grocery_item_id
|
||||
WHERE
|
||||
fi.master_item_id IN (SELECT master_item_id FROM UserWatchedItems)
|
||||
AND f.valid_to >= CURRENT_DATE -- Only consider active flyers
|
||||
AND fi.price_in_cents IS NOT NULL
|
||||
)
|
||||
-- Select only the #1 ranked (lowest) price for each item
|
||||
SELECT
|
||||
master_item_id,
|
||||
item_name,
|
||||
price_in_cents AS best_price_in_cents,
|
||||
store_name,
|
||||
flyer_id,
|
||||
valid_to
|
||||
FROM RankedPrices
|
||||
WHERE rn = 1
|
||||
ORDER BY item_name;
|
||||
`;
|
||||
const { rows } = await this.pool.query(query, [userId]);
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
export const dealsRepo = new DealsRepository();
|
||||
Reference in New Issue
Block a user