dataflow/api/routes/mappings.js

179 lines
5.4 KiB
JavaScript

/**
* Mappings Routes
* Manage value mappings
*/
const express = require('express');
module.exports = (pool) => {
const router = express.Router();
// List all mappings for a source
router.get('/source/:source_name', async (req, res, next) => {
try {
const { rule_name } = req.query;
let query = 'SELECT * FROM mappings WHERE source_name = $1';
const params = [req.params.source_name];
if (rule_name) {
query += ' AND rule_name = $2';
params.push(rule_name);
}
query += ' ORDER BY rule_name, input_value';
const result = await pool.query(query, params);
res.json(result.rows);
} catch (err) {
next(err);
}
});
// Get unmapped values
router.get('/source/:source_name/unmapped', async (req, res, next) => {
try {
const { rule_name } = req.query;
const result = await pool.query(
'SELECT * FROM get_unmapped_values($1, $2)',
[req.params.source_name, rule_name || null]
);
res.json(result.rows);
} catch (err) {
next(err);
}
});
// Get single mapping
router.get('/:id', async (req, res, next) => {
try {
const result = await pool.query(
'SELECT * FROM mappings WHERE id = $1',
[req.params.id]
);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'Mapping not found' });
}
res.json(result.rows[0]);
} catch (err) {
next(err);
}
});
// Create mapping
router.post('/', async (req, res, next) => {
try {
const { source_name, rule_name, input_value, output } = req.body;
if (!source_name || !rule_name || !input_value || !output) {
return res.status(400).json({
error: 'Missing required fields: source_name, rule_name, input_value, output'
});
}
const result = await pool.query(
`INSERT INTO mappings (source_name, rule_name, input_value, output)
VALUES ($1, $2, $3, $4)
RETURNING *`,
[source_name, rule_name, input_value, JSON.stringify(output)]
);
res.status(201).json(result.rows[0]);
} catch (err) {
if (err.code === '23505') { // Unique violation
return res.status(409).json({ error: 'Mapping already exists' });
}
if (err.code === '23503') { // Foreign key violation
return res.status(404).json({ error: 'Source or rule not found' });
}
next(err);
}
});
// Bulk create mappings
router.post('/bulk', async (req, res, next) => {
const client = await pool.connect();
try {
const { mappings } = req.body;
if (!Array.isArray(mappings)) {
return res.status(400).json({ error: 'Expected array of mappings' });
}
await client.query('BEGIN');
const results = [];
for (const mapping of mappings) {
const { source_name, rule_name, input_value, output } = mapping;
const result = await client.query(
`INSERT INTO mappings (source_name, rule_name, input_value, output)
VALUES ($1, $2, $3, $4)
ON CONFLICT (source_name, rule_name, input_value)
DO UPDATE SET output = EXCLUDED.output
RETURNING *`,
[source_name, rule_name, input_value, JSON.stringify(output)]
);
results.push(result.rows[0]);
}
await client.query('COMMIT');
res.status(201).json({ count: results.length, mappings: results });
} catch (err) {
await client.query('ROLLBACK');
next(err);
} finally {
client.release();
}
});
// Update mapping
router.put('/:id', async (req, res, next) => {
try {
const { input_value, output } = req.body;
const result = await pool.query(
`UPDATE mappings
SET input_value = COALESCE($2, input_value),
output = COALESCE($3, output)
WHERE id = $1
RETURNING *`,
[req.params.id, input_value, output ? JSON.stringify(output) : null]
);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'Mapping not found' });
}
res.json(result.rows[0]);
} catch (err) {
next(err);
}
});
// Delete mapping
router.delete('/:id', async (req, res, next) => {
try {
const result = await pool.query(
'DELETE FROM mappings WHERE id = $1 RETURNING id',
[req.params.id]
);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'Mapping not found' });
}
res.json({ success: true, deleted: result.rows[0].id });
} catch (err) {
next(err);
}
});
return router;
};