replacing db to caching Hash Obj

This commit is contained in:
Kfir Dayan 2023-04-26 19:32:22 +03:00
parent 931d41d04c
commit 9e437999f7
6 changed files with 105 additions and 27 deletions

View file

@ -25,22 +25,14 @@ init POSTGRES Database -
CREATE DATABASE drop_shopping; CREATE DATABASE drop_shopping;
create tables - create tables -
timeSlots - CREATE TABLE deliveries (
CREATE TABLE time_slots (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
start_time TIME NOT NULL, user_id INTEGER NOT NULL,
end_time TIME NOT NULL, slot_id INTEGER NOT NULL,
created_at TIMESTAMP DEFAULT NOW(), delivery_date DATE NOT NULL,
updated_at TIMESTAMP DEFAULT NOW() address TEXT NOT NULL,
); status VARCHAR(10) NOT NULL
);
holidays -
CREATE TABLE holidays (
id SERIAL PRIMARY KEY,
holiday_date DATE NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
knex for migration files knex for migration files

12
package-lock.json generated
View file

@ -20,6 +20,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^18.16.0", "@types/node": "^18.16.0",
"@types/pg": "^8.6.6",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
"ts-node-dev": "^2.0.0", "ts-node-dev": "^2.0.0",
"typescript": "^5.0.4" "typescript": "^5.0.4"
@ -134,6 +135,17 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.0.tgz",
"integrity": "sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==" "integrity": "sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ=="
}, },
"node_modules/@types/pg": {
"version": "8.6.6",
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.6.tgz",
"integrity": "sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==",
"dev": true,
"dependencies": {
"@types/node": "*",
"pg-protocol": "*",
"pg-types": "^2.2.0"
}
},
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",

View file

@ -22,6 +22,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^18.16.0", "@types/node": "^18.16.0",
"@types/pg": "^8.6.6",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
"ts-node-dev": "^2.0.0", "ts-node-dev": "^2.0.0",
"typescript": "^5.0.4" "typescript": "^5.0.4"

View file

@ -1,4 +1,5 @@
import express from 'express'; import express from 'express';
const stam = 'fds'
import routes from './routes'; import routes from './routes';
const app = express(); const app = express();

View file

@ -1,42 +1,114 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { resolveAddress } from './geocoding'; import { resolveAddress } from './geocoding';
import { Address, AvailableTimeslots } from './types'; import { Address, AvailableTimeslots } from './types';
import { randomUUID } from 'crypto';
// DOME // DOME
import { getAvailableTimeSlots } from './services/timeslotsService'; import { getAvailableTimeSlots } from './services/timeslotsService';
import { getHolidays } from './services/holidaysService'; import { getHolidays } from './services/holidaysService';
const env = require('dotenv');
// create a hashing for caching delivery slots. this needs to be a caching db.
const deliveriesCache = new Map();
// create a hashing for caching timeslots. this needs to be a caching db.
const slotsInUse = new Map();
export const resolveAddressHandler = (req: Request, res: Response) => { export const resolveAddressHandler = (req: Request, res: Response) => {
console.info("resolveAddressHandler called");
if (!req.body.searchTerm) { if (!req.body.searchTerm) {
res.status(400).json({ error: 'Missing searchTerm' }); res.status(400).json({ error: 'Missing searchTerm' });
return; return;
} }
const address: Promise<Address> = resolveAddress(req.body.searchTerm); const address: Promise<Address> = resolveAddress(req.body.searchTerm);
address.then((result) => { address.then((result) => {
console.info("resolveAddressHandler result: ", result);
res.status(200).json(result); res.status(200).json(result);
}) })
}; };
export const timeslotsHandler = async (req: Request, res: Response) => { export const timeslotsHandler = async (req: Request, res: Response) => {
// TODO: Implement timeslots functionality
if (!req.body.address) { if (!req.body.address) {
res.status(400).json({ error: 'Missing address' }); res.status(400).json({ error: 'Missing address' });
return; return;
} }
const address: Address = req.body.address; const address: Address = req.body.address;
const timeSlots: AvailableTimeslots[] = await availableTimeSlots(address); const timeSlots: AvailableTimeslots[] = await availableTimeSlots(address);
const availableTimeSlotsResult = await filterOutHolidaysByCountryCode(address, timeSlots); const availableTimeSlotsResult: AvailableTimeslots[] = await filterOutHolidaysByCountryCode(address, timeSlots);
availableTimeSlotsResult.forEach((timeSlot, index) => {
if (slotsInUse.has(timeSlot.id) && slotsInUse.get(timeSlot.id).length >= 2) {
availableTimeSlotsResult.splice(index, 1);
}
});
res.status(200).json(availableTimeSlotsResult); res.status(200).json(availableTimeSlotsResult);
}; };
export const deliveriesHandler = (req: Request, res: Response) => { export const deliveriesHandler = (req: Request, res: Response) => {
// TODO: Implement deliveries functionality const userId = req.body.userId;
const slotId = req.body.timeslotId;
// Idea: validate userId and slotId needed
if (!userId || !slotId) {
res.status(400).json({ error: 'Missing userId or slotId' });
return;
}
// Idea: check if user has already booked a delivery
// if (deliveriesCache.has(userId) && deliveriesCache.get(userId).slotId === slotId) {
// res.status(400).json({ error: 'User has already booked a delivery' });
// return;
// }
// Idea: check if timeslot is already full in cache
if (slotsInUse.has(slotId) && slotsInUse.get(slotId).length >= 2) {
res.status(400).json({ error: 'This timeslot is already full' });
return;
}
const deliveryId = randomUUID();
// Idea: create new delivery for user
const delivery = {
_id: deliveryId,
userId,
slotId,
deliveryCreatedDate: new Date()
};
if (slotsInUse.has(slotId)) {
slotsInUse.get(slotId).push(deliveryId);
} else {
slotsInUse.set(slotId, [deliveryId]);
}
deliveriesCache.set(deliveryId, delivery);
console.log("deliveriesCache", deliveriesCache)
console.log("slotsInUse", slotsInUse)
res.status(200).json(delivery);
}; };
export const cancelDeliveryHandler = (req: Request, res: Response) => { export const cancelDeliveryHandler = (req: Request, res: Response) => {
// TODO: Implement cancel delivery functionality // TODO: Implement cancel delivery functionality
// DELETE /deliveries/:deliveryId
const deliveryId = req.params.deliveryId;
if (!deliveryId) {
res.status(400).json({ error: 'Missing deliveryId' });
return;
}
// remove from deliveriesCache and extract slotId
const delivery = deliveriesCache.get(deliveryId);
if (!delivery) {
res.status(400).json({ error: 'Delivery not found' });
return;
}
const slotId = delivery.slotId;
deliveriesCache.delete(deliveryId);
// remove from slotsInUse by slotId
const slot = slotsInUse.get(slotId);
const index = slot.indexOf(deliveryId);
if (index > -1) {
slot.splice(index, 1);
}
res.status(200).json(delivery);
}; };
export const dailyDeliveriesHandler = (req: Request, res: Response) => { export const dailyDeliveriesHandler = (req: Request, res: Response) => {
@ -49,18 +121,17 @@ export const weeklyDeliveriesHandler = (req: Request, res: Response) => {
async function filterOutHolidaysByCountryCode(address: Address, availableTimeSlot: AvailableTimeslots[]) { async function filterOutHolidaysByCountryCode(address: Address, availableTimeSlot: AvailableTimeslots[]): Promise<AvailableTimeslots[]> {
const countryCode = address.code; const countryCode = address.code;
const holidays = await getHolidays(); const holidays = await getHolidays();
const filteredAvailableTimeSlot = []; const filteredAvailableTimeSlot = [];
console.log(availableTimeSlot) console.log(availableTimeSlot)
holidays.forEach((holiday) => { holidays.forEach((holiday) => {
if(holiday.country === countryCode) { if (holiday.country === countryCode) {
availableTimeSlot.forEach((timeSlot) => { availableTimeSlot.forEach((timeSlot) => {
if(timeSlot.start_time.split(' ')[0] !== holiday.date) { if (timeSlot.start_time.split(' ')[0] !== holiday.date) {
filteredAvailableTimeSlot.push(timeSlot) filteredAvailableTimeSlot.push(timeSlot)
} }
}) })
@ -77,6 +148,7 @@ async function availableTimeSlots(address: Address) {
for (const timeslot of timeslots.courier_available_timeslots) { for (const timeslot of timeslots.courier_available_timeslots) {
if (timeslot.supported_postcodes.includes(address.postcode)) { if (timeslot.supported_postcodes.includes(address.postcode)) {
availableTimeSlot.push({ availableTimeSlot.push({
id: timeslot.id,
start_time: timeslot.start_time, start_time: timeslot.start_time,
end_time: timeslot.end_time end_time: timeslot.end_time
}); });

View file

@ -4,10 +4,10 @@ import { resolveAddressHandler, timeslotsHandler, deliveriesHandler, cancelDeliv
const router = express.Router(); const router = express.Router();
router.post('/resolve-address', resolveAddressHandler); router.post('/resolve-address', resolveAddressHandler);
router.delete('/deliveries/:deliveryId', cancelDeliveryHandler);
router.post('/timeslots', timeslotsHandler); router.post('/timeslots', timeslotsHandler);
router.get('/deliveries/daily', dailyDeliveriesHandler); router.get('/deliveries/daily', dailyDeliveriesHandler);
router.get('/deliveries/weekly', weeklyDeliveriesHandler); router.get('/deliveries/weekly', weeklyDeliveriesHandler);
router.post('/deliveries', deliveriesHandler); router.post('/deliveries', deliveriesHandler);
router.delete('/deliveries/:id', cancelDeliveryHandler);
export default router; export default router;