|
1 | 1 | import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; |
2 | | -import { dirname, resolve } from 'node:path'; |
3 | 2 | import { randomBytes, randomUUID, scryptSync, timingSafeEqual } from 'node:crypto'; |
| 3 | +import { dirname, resolve } from 'node:path'; |
4 | 4 |
|
5 | | -const defaultDbPath = resolve(process.cwd(), 'backend', 'data', 'brocode.sqlite'); |
| 5 | +const defaultDbPath = resolve(process.cwd(), 'backend', 'data', 'brocode.json'); |
6 | 6 | const dbPath = process.env.BROCODE_DB_PATH ? resolve(process.env.BROCODE_DB_PATH) : defaultDbPath; |
7 | 7 |
|
8 | 8 | const dbDirectory = dirname(dbPath); |
@@ -34,79 +34,6 @@ const verifyPassword = (password, storedPassword) => { |
34 | 34 | return timingSafeEqual(candidateHash, expectedHash); |
35 | 35 | }; |
36 | 36 |
|
37 | | -db.exec(` |
38 | | - CREATE TABLE IF NOT EXISTS users ( |
39 | | - id TEXT PRIMARY KEY, |
40 | | - username TEXT NOT NULL UNIQUE, |
41 | | - password TEXT NOT NULL, |
42 | | - name TEXT NOT NULL, |
43 | | - role TEXT NOT NULL |
44 | | - ); |
45 | | -
|
46 | | - CREATE TABLE IF NOT EXISTS spots ( |
47 | | - id TEXT PRIMARY KEY, |
48 | | - location TEXT NOT NULL, |
49 | | - date TEXT NOT NULL, |
50 | | - host_user_id TEXT NOT NULL, |
51 | | - FOREIGN KEY (host_user_id) REFERENCES users(id) ON DELETE CASCADE |
52 | | - ); |
53 | | -
|
54 | | - CREATE TABLE IF NOT EXISTS catalog_items ( |
55 | | - id TEXT PRIMARY KEY, |
56 | | - category TEXT NOT NULL, |
57 | | - name TEXT NOT NULL, |
58 | | - price REAL NOT NULL |
59 | | - ); |
60 | | -
|
61 | | - CREATE TABLE IF NOT EXISTS orders ( |
62 | | - id TEXT PRIMARY KEY, |
63 | | - spot_id TEXT NOT NULL, |
64 | | - user_id TEXT NOT NULL, |
65 | | - total_amount REAL NOT NULL, |
66 | | - created_at TEXT NOT NULL, |
67 | | - FOREIGN KEY (spot_id) REFERENCES spots(id), |
68 | | - FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE |
69 | | - ); |
70 | | -
|
71 | | - CREATE TABLE IF NOT EXISTS order_items ( |
72 | | - id INTEGER PRIMARY KEY AUTOINCREMENT, |
73 | | - order_id TEXT NOT NULL, |
74 | | - product_id TEXT NOT NULL, |
75 | | - name TEXT NOT NULL, |
76 | | - quantity INTEGER NOT NULL, |
77 | | - unit_price REAL NOT NULL, |
78 | | - total REAL NOT NULL, |
79 | | - FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE |
80 | | - ); |
81 | | -`); |
82 | | - |
83 | | -const hasUsers = db.prepare('SELECT COUNT(*) AS count FROM users').get().count > 0; |
84 | | - |
85 | | -if (!hasUsers) { |
86 | | - const insertUser = db.prepare('INSERT INTO users (id, username, password, name, role) VALUES (?, ?, ?, ?, ?)'); |
87 | | - insertUser.run('u-1', 'brocode', hashPassword('changeme'), 'Ram', 'admin'); |
88 | | - insertUser.run('u-2', 'dhanush', hashPassword('changeme'), 'Dhanush', 'user'); |
89 | | - |
90 | | - const insertSpot = db.prepare('INSERT INTO spots (id, location, date, host_user_id) VALUES (?, ?, ?, ?)'); |
91 | | - insertSpot.run('spot-2025-07-26', 'Attibele Toll Plaza', '2025-07-26T10:00:00.000Z', 'u-1'); |
92 | | - |
93 | | - const insertCatalogItem = db.prepare('INSERT INTO catalog_items (id, category, name, price) VALUES (?, ?, ?, ?)'); |
94 | | - insertCatalogItem.run('d-1', 'drinks', 'Brocode Beer', 180); |
95 | | - insertCatalogItem.run('d-2', 'drinks', 'Kingfisher Beer', 170); |
96 | | - insertCatalogItem.run('f-1', 'food', 'Beef Biriyani', 220); |
97 | | - insertCatalogItem.run('f-2', 'food', 'Parotta', 30); |
98 | | - insertCatalogItem.run('c-1', 'cigarettes', 'Marlboro', 25); |
99 | | - insertCatalogItem.run('c-2', 'cigarettes', 'Classic', 20); |
100 | | - |
101 | | - db.prepare( |
102 | | - 'INSERT INTO orders (id, spot_id, user_id, total_amount, created_at) VALUES (?, ?, ?, ?, ?)' |
103 | | - ).run('ord-1', 'spot-2025-07-26', 'u-2', 360, '2025-07-26T10:30:00.000Z'); |
104 | | - |
105 | | - db.prepare( |
106 | | - `INSERT INTO order_items (order_id, product_id, name, quantity, unit_price, total) |
107 | | - VALUES (?, ?, ?, ?, ?, ?)` |
108 | | - ).run('ord-1', 'd-1', 'Brocode Beer', 2, 180, 360); |
109 | | -} |
110 | 37 | const seedData = () => ({ |
111 | 38 | users: [ |
112 | 39 | { id: 'u-1', username: 'brocode', password: hashPassword('changeme'), name: 'Ram', role: 'admin' }, |
@@ -196,42 +123,6 @@ const mapOrder = (order, items) => ({ |
196 | 123 | })), |
197 | 124 | }); |
198 | 125 |
|
199 | | -const fetchOrderItemsByOrderIds = (orderIds) => { |
200 | | - if (orderIds.length === 0) return new Map(); |
201 | | - |
202 | | - const placeholders = orderIds.map(() => '?').join(','); |
203 | | - const rows = db |
204 | | - .prepare( |
205 | | - `SELECT order_id, product_id, name, quantity, unit_price, total |
206 | | - FROM order_items |
207 | | - WHERE order_id IN (${placeholders}) |
208 | | - ORDER BY id ASC` |
209 | | - ) |
210 | | - .all(...orderIds); |
211 | | - |
212 | | - const itemsByOrderId = new Map(); |
213 | | - rows.forEach((row) => { |
214 | | - if (!itemsByOrderId.has(row.order_id)) { |
215 | | - itemsByOrderId.set(row.order_id, []); |
216 | | - } |
217 | | - itemsByOrderId.get(row.order_id).push(row); |
218 | | - }); |
219 | | - |
220 | | - return itemsByOrderId; |
221 | | -}; |
222 | | - |
223 | | -const getCatalogItemByIdStatement = db.prepare( |
224 | | - 'SELECT id, category, name, price FROM catalog_items WHERE id = ?' |
225 | | -); |
226 | | - |
227 | | -const userExistsStatement = db.prepare('SELECT 1 AS found FROM users WHERE id = ? LIMIT 1'); |
228 | | -const spotExistsStatement = db.prepare('SELECT 1 AS found FROM spots WHERE id = ? LIMIT 1'); |
229 | | -const getUserByUsernameStatement = db.prepare('SELECT id, username, password, name, role FROM users WHERE username = ?'); |
230 | | -const updateUserPasswordStatement = db.prepare('UPDATE users SET password = ? WHERE id = ?'); |
231 | | -const deleteUserByIdStatement = db.prepare('DELETE FROM users WHERE id = ?'); |
232 | | -const deleteOrdersByUserIdStatement = db.prepare('DELETE FROM orders WHERE user_id = ?'); |
233 | | -const deleteSpotsByHostUserIdStatement = db.prepare('DELETE FROM spots WHERE host_user_id = ?'); |
234 | | - |
235 | 126 | export const database = { |
236 | 127 | getUserByCredentials(username, password) { |
237 | 128 | const user = state.users.find((entry) => entry.username === username); |
@@ -303,6 +194,20 @@ export const database = { |
303 | 194 | }); |
304 | 195 | }, |
305 | 196 |
|
| 197 | + getOrderById(orderId) { |
| 198 | + const order = state.orders.find((entry) => entry.id === orderId); |
| 199 | + |
| 200 | + if (!order) { |
| 201 | + return null; |
| 202 | + } |
| 203 | + |
| 204 | + const orderItems = state.order_items |
| 205 | + .filter((item) => item.order_id === order.id) |
| 206 | + .sort((a, b) => a.id - b.id); |
| 207 | + |
| 208 | + return mapOrder(order, orderItems); |
| 209 | + }, |
| 210 | + |
306 | 211 | createOrder({ spotId, userId, items }) { |
307 | 212 | const parsedItems = items.map((item) => { |
308 | 213 | const quantity = Number(item.quantity || 0); |
@@ -361,18 +266,15 @@ export const database = { |
361 | 266 | }, |
362 | 267 |
|
363 | 268 | deleteUserCompletely(userId) { |
364 | | - db.exec('BEGIN'); |
| 269 | + const hostedSpotIds = new Set(state.spots.filter((spot) => spot.host_user_id === userId).map((spot) => spot.id)); |
365 | 270 |
|
366 | | - try { |
367 | | - deleteOrdersByUserIdStatement.run(userId); |
368 | | - deleteSpotsByHostUserIdStatement.run(userId); |
369 | | - deleteUserByIdStatement.run(userId); |
| 271 | + state.users = state.users.filter((user) => user.id !== userId); |
| 272 | + state.orders = state.orders.filter((order) => order.user_id !== userId && !hostedSpotIds.has(order.spot_id)); |
| 273 | + const activeOrderIds = new Set(state.orders.map((order) => order.id)); |
| 274 | + state.order_items = state.order_items.filter((item) => activeOrderIds.has(item.order_id)); |
| 275 | + state.spots = state.spots.filter((spot) => spot.host_user_id !== userId); |
370 | 276 |
|
371 | | - db.exec('COMMIT'); |
372 | | - } catch (error) { |
373 | | - db.exec('ROLLBACK'); |
374 | | - throw error; |
375 | | - } |
| 277 | + persist(); |
376 | 278 | }, |
377 | 279 |
|
378 | 280 | getBillBySpotId(spotId) { |
|
0 commit comments