diff --git a/server/routes/genetics.js b/server/routes/genetics.js new file mode 100644 index 0000000..4437b62 --- /dev/null +++ b/server/routes/genetics.js @@ -0,0 +1,158 @@ +const express = require('express'); +const router = express.Router(); +const { getDatabase } = require('../db/init'); + +// Golden Retriever panel markers tracked by Breedr +const GR_MARKERS = [ + 'PRA1', 'PRA2', 'prcd-PRA', 'GR-PRA1', 'GR-PRA2', + 'ICH1', 'ICH2', 'NCL', 'DM', 'MD' +]; + +// GET all genetic tests for a dog +router.get('/dog/:dogId', (req, res) => { + try { + const db = getDatabase(); + const tests = db.prepare(` + SELECT * FROM genetic_tests + WHERE dog_id = ? + ORDER BY marker ASC + `).all(req.params.dogId); + + // Return a full panel including not_tested placeholders + const byMarker = {}; + for (const t of tests) byMarker[t.marker] = t; + + const panel = GR_MARKERS.map(marker => ({ + marker, + ...(byMarker[marker] || { result: 'not_tested', dog_id: Number(req.params.dogId) }) + })); + + res.json({ tests, panel }); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +// GET pairing risk — compare sire + dam carrier status +// Usage: GET /api/genetics/pairing-risk?sireId=1&damId=2 +router.get('/pairing-risk', (req, res) => { + try { + const { sireId, damId } = req.query; + if (!sireId || !damId) { + return res.status(400).json({ error: 'sireId and damId are required' }); + } + + const db = getDatabase(); + + const getResults = (dogId) => { + const rows = db.prepare('SELECT marker, result FROM genetic_tests WHERE dog_id = ?').all(dogId); + const map = {}; + for (const r of rows) map[r.marker] = r.result; + return map; + }; + + const sireResults = getResults(sireId); + const damResults = getResults(damId); + + const risks = []; + for (const marker of GR_MARKERS) { + const s = sireResults[marker] || 'not_tested'; + const d = damResults[marker] || 'not_tested'; + + // Both affected or carrier x carrier = risk + if ( + (s === 'affected' || d === 'affected') || + (s === 'carrier' && d === 'carrier') + ) { + risks.push({ + marker, + sire_result: s, + dam_result: d, + risk_level: (s === 'affected' || d === 'affected') ? 'high' : 'moderate', + note: s === 'affected' || d === 'affected' + ? 'One or both parents are affected — do not breed' + : 'Both parents are carriers — 25% chance of affected offspring', + }); + } + } + + res.json({ + sire_id: Number(sireId), + dam_id: Number(damId), + risks, + safe_to_pair: risks.length === 0, + }); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +// GET single genetic test +router.get('/:id', (req, res) => { + try { + const db = getDatabase(); + const test = db.prepare('SELECT * FROM genetic_tests WHERE id = ?').get(req.params.id); + if (!test) return res.status(404).json({ error: 'Genetic test not found' }); + res.json(test); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +// POST create genetic test +router.post('/', (req, res) => { + try { + const { dog_id, test_provider, marker, result, test_date, document_url, notes } = req.body; + + if (!dog_id || !marker || !result) { + return res.status(400).json({ error: 'dog_id, marker, and result are required' }); + } + if (!['clear', 'carrier', 'affected', 'not_tested'].includes(result)) { + return res.status(400).json({ error: 'result must be: clear | carrier | affected | not_tested' }); + } + + const db = getDatabase(); + const dbResult = db.prepare(` + INSERT INTO genetic_tests (dog_id, test_provider, marker, result, test_date, document_url, notes) + VALUES (?, ?, ?, ?, ?, ?, ?) + `).run(dog_id, test_provider || null, marker, result, test_date || null, document_url || null, notes || null); + + const test = db.prepare('SELECT * FROM genetic_tests WHERE id = ?').get(dbResult.lastInsertRowid); + res.status(201).json(test); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +// PUT update genetic test +router.put('/:id', (req, res) => { + try { + const { test_provider, marker, result, test_date, document_url, notes } = req.body; + + const db = getDatabase(); + db.prepare(` + UPDATE genetic_tests + SET test_provider = ?, marker = ?, result = ?, test_date = ?, + document_url = ?, notes = ?, updated_at = datetime('now') + WHERE id = ? + `).run(test_provider || null, marker, result, test_date || null, document_url || null, notes || null, req.params.id); + + const test = db.prepare('SELECT * FROM genetic_tests WHERE id = ?').get(req.params.id); + res.json(test); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +// DELETE genetic test +router.delete('/:id', (req, res) => { + try { + const db = getDatabase(); + db.prepare('DELETE FROM genetic_tests WHERE id = ?').run(req.params.id); + res.json({ message: 'Genetic test deleted successfully' }); + } catch (error) { + res.status(500).json({ error: error.message }); + } +}); + +module.exports = router;