replacing db to caching Hash Obj
This commit is contained in:
parent
931d41d04c
commit
9e437999f7
6 changed files with 105 additions and 27 deletions
24
README.md
24
README.md
|
@ -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,
|
user_id INTEGER NOT NULL,
|
||||||
start_time TIME NOT NULL,
|
slot_id INTEGER NOT NULL,
|
||||||
end_time TIME NOT NULL,
|
delivery_date DATE NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT NOW(),
|
address TEXT NOT NULL,
|
||||||
updated_at TIMESTAMP DEFAULT NOW()
|
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
12
package-lock.json
generated
|
@ -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",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
});
|
});
|
||||||
|
|
|
@ -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;
|
Loading…
Reference in a new issue