Files
LabWise/server/src/routes/chemicals.ts

107 lines
3.6 KiB
TypeScript
Raw Normal View History

import { Router } from 'express';
import { pool } from '../db/pool';
import { requireAuth } from '../auth/middleware';
const router = Router();
router.use(requireAuth);
function camelToSnake(str: string): string {
return str.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`);
}
// GET /api/chemicals
router.get('/', async (req, res) => {
try {
const result = await pool.query(
'SELECT * FROM chemicals WHERE user_id = $1 ORDER BY created_at DESC',
[req.user!.id]
);
// Map snake_case columns back to camelCase for the frontend
const rows = result.rows.map(snakeToCamel);
res.json(rows);
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
// POST /api/chemicals
router.post('/', async (req, res) => {
try {
const b = req.body;
const result = await pool.query(`
INSERT INTO chemicals (
user_id, pi_first_name, physical_state, chemical_name, bldg_code, lab,
storage_location, storage_device, number_of_containers, amount_per_container,
unit_of_measure, cas_number,
chemical_formula, molecular_weight, vendor, catalog_number, lot_number,
expiration_date, concentration, percentage_full, needs_manual_entry,
scanned_image, comments, barcode, contact
) VALUES (
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,
$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25
) RETURNING *`,
[
req.user!.id, b.piFirstName, b.physicalState, b.chemicalName, b.bldgCode, b.lab,
b.storageLocation, b.storageDevice, b.numberOfContainers, b.amountPerContainer,
b.unitOfMeasure, b.casNumber,
b.chemicalFormula ?? null, b.molecularWeight ?? null, b.vendor ?? null,
b.catalogNumber ?? null, b.lotNumber ?? null,
b.expirationDate ?? null, b.concentration ?? null,
b.percentageFull ?? null, b.needsManualEntry ?? null,
b.scannedImage ?? null, b.comments ?? null, b.barcode ?? null, b.contact ?? null,
]
);
res.status(201).json(snakeToCamel(result.rows[0]));
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
// PATCH /api/chemicals/:id
router.patch('/:id', async (req, res) => {
try {
const fields = Object.keys(req.body);
if (fields.length === 0) return res.status(400).json({ error: 'No fields to update' });
const snakeFields = fields.map(camelToSnake);
const setClauses = snakeFields.map((f, i) => `${f} = $${i + 3}`).join(', ');
const values = fields.map(f => req.body[f]);
const result = await pool.query(
`UPDATE chemicals SET ${setClauses}, updated_at = NOW()
WHERE id = $1 AND user_id = $2 RETURNING *`,
[req.params.id, req.user!.id, ...values]
);
if (result.rows.length === 0) return res.status(404).json({ error: 'Not found' });
res.json(snakeToCamel(result.rows[0]));
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
// DELETE /api/chemicals/:id
router.delete('/:id', async (req, res) => {
try {
await pool.query('DELETE FROM chemicals WHERE id = $1 AND user_id = $2',
[req.params.id, req.user!.id]);
res.status(204).end();
} catch (err) {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
}
});
function snakeToCamel(row: Record<string, unknown>): Record<string, unknown> {
return Object.fromEntries(
Object.entries(row).map(([k, v]) => [
k.replace(/_([a-z])/g, (_, l) => l.toUpperCase()),
v,
])
);
}
export default router;