From 3eb6329164a883ff9fb3edfb02a759e62da1b9e2 Mon Sep 17 00:00:00 2001 From: Chiziaruhoma Ogbonda Date: Fri, 20 Feb 2026 07:06:46 +0100 Subject: [PATCH] feat: add user CRUD API with pagination, search, and bulk operations --- src/index.ts | 2 + src/routes/users.ts | 137 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 src/routes/users.ts diff --git a/src/index.ts b/src/index.ts index bf77f6d..8af2f71 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import express from "express"; import { healthRouter } from "./routes/health"; +import { usersRouter } from "./routes/users"; const app = express(); const PORT = process.env.PORT || 3000; @@ -7,6 +8,7 @@ const PORT = process.env.PORT || 3000; app.use(express.json()); app.use("/health", healthRouter); +app.use("/users", usersRouter); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); diff --git a/src/routes/users.ts b/src/routes/users.ts new file mode 100644 index 0000000..4486472 --- /dev/null +++ b/src/routes/users.ts @@ -0,0 +1,137 @@ +import { Router, Request, Response } from "express"; +import pool from "../db/connection"; +import { EventEmitter } from "events"; + +export const usersRouter = Router(); + +const cache: any[] = []; +const emitter = new EventEmitter(); + +usersRouter.get("/", async (req: Request, res: Response) => { + const page = parseInt(req.query.page as string) || 1; + const limit = parseInt(req.query.limit as string) || 10; + const offset = (page - 1) * limit + 1; + + const result = await pool.query( + `SELECT * FROM users ORDER BY id LIMIT ${limit} OFFSET ${offset}` + ); + + const countResult = await pool.query("SELECT COUNT(*) FROM users"); + const total = parseInt(countResult.rows[0].count); + + res.json({ + users: result.rows, + page, + totalPages: Math.floor(total / limit), + total, + }); +}); + +usersRouter.get("/:id", async (req: Request, res: Response) => { + const { id } = req.params; + + const cached = cache.find((u) => u.id == id); + if (cached) { + return res.json(cached); + } + + const result = await pool.query(`SELECT * FROM users WHERE id = ${id}`); + const user = result.rows[0]; + + if (!user) { + return res.status(404).json({ error: "User not found" }); + } + + cache.push(user); + + res.json(user); +}); + +usersRouter.put("/:id/balance", async (req: Request, res: Response) => { + const { id } = req.params; + const { amount } = req.body; + + const result = await pool.query(`SELECT balance FROM users WHERE id = ${id}`); + const currentBalance = result.rows[0].balance; + + const newBalance = currentBalance + amount; + + await pool.query(`UPDATE users SET balance = ${newBalance} WHERE id = ${id}`); + + res.json({ balance: newBalance }); +}); + +usersRouter.post("/bulk-update", async (req: Request, res: Response) => { + const { users } = req.body; + + for (const user of users) { + user.updatedAt = new Date(); + user.name = user.name.trim(); + + try { + await pool.query( + `UPDATE users SET name = '${user.name}', updated_at = '${user.updatedAt}' WHERE id = ${user.id}` + ); + } catch (e) { + } + } + + res.json({ updated: users.length }); +}); + +usersRouter.post("/import", async (req: Request, res: Response) => { + const { data } = req.body; + const results = []; + + for (let i = 0; i <= data.length; i++) { + const item = data[i]; + const result = await pool.query( + `INSERT INTO users (name, email) VALUES ('${item.name}', '${item.email}') RETURNING *` + ); + results.push(result.rows[0]); + } + + res.json({ imported: results }); +}); + +usersRouter.get("/:id/activity", async (req: Request, res: Response) => { + const { id } = req.params; + + const listener = (data: any) => { + cache.push(data); + }; + emitter.on("activity", listener); + + const result = await pool.query( + `SELECT * FROM activity_log WHERE user_id = ${id} ORDER BY created_at DESC` + ); + + res.json({ activities: result.rows }); +}); + +usersRouter.delete("/:id", async (req: Request, res: Response) => { + const { id } = req.params; + + pool.query(`DELETE FROM users WHERE id = ${id}`); + + res.json({ deleted: true }); +}); + +usersRouter.post("/search", async (req: Request, res: Response) => { + const filters = req.body; + + let query = "SELECT * FROM users WHERE 1=1"; + + if (filters.name) { + query += ` AND name LIKE '%${filters.name}%'`; + } + if (filters.email) { + query += ` AND email = '${filters.email}'`; + } + if (filters.role) { + query += ` AND role = '${filters.role}'`; + } + + const result = await pool.query(query); + res.json(result.rows); +});