Feat: agregar soporte para MariaDB y API routes individuales
- Crear server/db-mariadb.js con conexión a MariaDB usando los datos proporcionados - Crear server/api-mariadb.js con endpoints individuales para todas las entidades - Crear server/migrate-to-mariadb.js para migrar datos de SQLite a MariaDB - Todas las operaciones CRUD disponibles via API REST
This commit is contained in:
@@ -0,0 +1,657 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import { initDb,
|
||||
getUsuarioByDni, getUsuarioById, getAllUsuarios, createUsuario, updateUsuario, deleteUsuario, verifyPassword, hashPassword,
|
||||
getAllPacientes, getPacienteById, createPaciente, updatePaciente, deletePaciente,
|
||||
getAllAreas, createArea, updateArea, deleteArea,
|
||||
getAllCamas, getCamaById, createCama, updateCama, deleteCama,
|
||||
getAllInternaciones, getInternacionById, createInternacion, updateInternacion, deleteInternacion,
|
||||
getAllEvoluciones, createEvolucion, updateEvolucion, deleteEvolucion,
|
||||
getAllLaboratorios, createLaboratorio, updateLaboratorio, deleteLaboratorio,
|
||||
getAllAcidosBase, createAcidoBase, deleteAcidoBase,
|
||||
getAllCultivos, createCultivo, updateCultivo, deleteCultivo,
|
||||
getAllEstudiosComplementarios, createEstudioComplementario, deleteEstudioComplementario,
|
||||
getAllInterconsultas, createInterconsulta, updateInterconsulta, deleteInterconsulta,
|
||||
getAllAtb, createAtb, deleteAtb,
|
||||
getAllIndicaciones, createIndicacion, updateIndicacion, deleteIndicacion,
|
||||
getAllMovimientosIndicaciones, createMovimientoIndicacion,
|
||||
getValue, setValue
|
||||
} from './db-mariadb.js';
|
||||
|
||||
const app = express();
|
||||
app.use(cors());
|
||||
app.use(express.json({ limit: '50mb' }));
|
||||
|
||||
// UUID generator
|
||||
function generateUUID() {
|
||||
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||||
const r = (Math.random() * 16) | 0;
|
||||
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
// ========== STATE ENDPOINT (initial load) ==========
|
||||
app.get('/api/state', async (req, res) => {
|
||||
try {
|
||||
const state = {
|
||||
pacientes: await getAllPacientes(),
|
||||
areas: await getAllAreas(),
|
||||
camas: await getAllCamas(),
|
||||
internaciones: await getAllInternaciones(),
|
||||
evoluciones: (await getAllEvoluciones()).map(e => ({
|
||||
...e,
|
||||
signosVitales: typeof e.signosVitales === 'string' ? JSON.parse(e.signosVitales) : e.signosVitales,
|
||||
examenFisico: typeof e.examenFisico === 'string' ? JSON.parse(e.examenFisico) : e.examenFisico
|
||||
})),
|
||||
laboratorios: (await getAllLaboratorios()).map(l => ({ ...l, resultados: typeof l.resultados === 'string' ? JSON.parse(l.resultados) : l.resultados })),
|
||||
acidosBase: await getAllAcidosBase(),
|
||||
cultivos: await getAllCultivos(),
|
||||
estudiosComplementarios: await getAllEstudiosComplementarios(),
|
||||
interconsultas: (await getAllInterconsultas()).map(ic => ({ ...ic, realizada: !!ic.realizada })),
|
||||
atb: await getAllAtb(),
|
||||
indicaciones: await getAllIndicaciones(),
|
||||
movimientosIndicaciones: await getAllMovimientosIndicaciones(),
|
||||
vistaActual: 'dashboard',
|
||||
currentInternacionId: null
|
||||
};
|
||||
res.json(state);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'failed to read state' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== USUARIOS ==========
|
||||
app.get('/api/usuarios', async (req, res) => {
|
||||
try {
|
||||
const usuarios = await getAllUsuarios();
|
||||
const usuariosSinPassword = usuarios.map(({ passwordHash, ...u }) => u);
|
||||
res.json(usuariosSinPassword);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener usuarios' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/usuarios', async (req, res) => {
|
||||
try {
|
||||
const { apellido, nombre, dni, fechaNacimiento, email, rol, matriculaProfesional, password, areaId } = req.body;
|
||||
|
||||
if (!apellido || !nombre || !dni || !fechaNacimiento || !email || !rol || !password) {
|
||||
return res.status(400).json({ error: 'Todos los campos obligatorios deben estar presentes' });
|
||||
}
|
||||
|
||||
const existente = await getUsuarioByDni(dni);
|
||||
if (existente) {
|
||||
return res.status(400).json({ error: 'Ya existe un usuario con ese DNI' });
|
||||
}
|
||||
|
||||
const passwordHash = hashPassword(password);
|
||||
const usuario = {
|
||||
id: generateUUID(),
|
||||
apellido, nombre, dni, fechaNacimiento, email, rol,
|
||||
matriculaProfesional: matriculaProfesional || null,
|
||||
passwordHash,
|
||||
areaId: areaId || null,
|
||||
fechaCreacion: new Date().toISOString().split('T')[0]
|
||||
};
|
||||
|
||||
await createUsuario(usuario);
|
||||
res.json({ ...usuario, passwordHash: undefined });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear usuario' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/usuarios/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { apellido, nombre, fechaNacimiento, email, rol, matriculaProfesional, areaId, password } = req.body;
|
||||
|
||||
const usuario = await getUsuarioById(id);
|
||||
if (!usuario) {
|
||||
return res.status(404).json({ error: 'Usuario no encontrado' });
|
||||
}
|
||||
|
||||
const datos = {};
|
||||
if (apellido !== undefined) datos.apellido = apellido;
|
||||
if (nombre !== undefined) datos.nombre = nombre;
|
||||
if (fechaNacimiento !== undefined) datos.fechaNacimiento = fechaNacimiento;
|
||||
if (email !== undefined) datos.email = email;
|
||||
if (rol !== undefined) datos.rol = rol;
|
||||
if (matriculaProfesional !== undefined) datos.matriculaProfesional = matriculaProfesional;
|
||||
if (areaId !== undefined) datos.areaId = areaId;
|
||||
if (password) datos.passwordHash = hashPassword(password);
|
||||
|
||||
await updateUsuario(id, datos);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar usuario' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/usuarios/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteUsuario(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar usuario' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== PACIENTES ==========
|
||||
app.get('/api/pacientes', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllPacientes());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener pacientes' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/pacientes', async (req, res) => {
|
||||
try {
|
||||
const paciente = { ...req.body, id: generateUUID() };
|
||||
await createPaciente(paciente);
|
||||
res.json(paciente);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear paciente' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/pacientes/:id', async (req, res) => {
|
||||
try {
|
||||
await updatePaciente(req.params.id, req.body);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar paciente' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/pacientes/:id', async (req, res) => {
|
||||
try {
|
||||
await deletePaciente(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar paciente' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== AREAS ==========
|
||||
app.get('/api/areas', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllAreas());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener areas' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/areas', async (req, res) => {
|
||||
try {
|
||||
const area = { ...req.body, id: generateUUID() };
|
||||
await createArea(area);
|
||||
res.json(area);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear area' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/areas/:id', async (req, res) => {
|
||||
try {
|
||||
await updateArea(req.params.id, req.body);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar area' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/areas/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteArea(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar area' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== CAMAS ==========
|
||||
app.get('/api/camas', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllCamas());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener camas' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/camas/:id', async (req, res) => {
|
||||
try {
|
||||
await updateCama(req.params.id, req.body);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar cama' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/camas', async (req, res) => {
|
||||
try {
|
||||
const cama = { ...req.body, id: generateUUID() };
|
||||
await createCama(cama);
|
||||
res.json(cama);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear cama' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/camas/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteCama(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar cama' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== INTERNACIONES ==========
|
||||
app.get('/api/internaciones', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllInternaciones());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener internaciones' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/internaciones', async (req, res) => {
|
||||
try {
|
||||
const internacion = { ...req.body, id: generateUUID(), activa: true };
|
||||
await createInternacion(internacion);
|
||||
res.json(internacion);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear internacion' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/internaciones/:id', async (req, res) => {
|
||||
try {
|
||||
await updateInternacion(req.params.id, req.body);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar internacion' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/internaciones/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteInternacion(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar internacion' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== EVOLUCIONES ==========
|
||||
app.get('/api/evoluciones', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllEvoluciones());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener evoluciones' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/evoluciones', async (req, res) => {
|
||||
try {
|
||||
const evolucion = { ...req.body, id: generateUUID() };
|
||||
await createEvolucion(evolucion);
|
||||
res.json(evolucion);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear evolucion' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/evoluciones/:id', async (req, res) => {
|
||||
try {
|
||||
await updateEvolucion(req.params.id, req.body);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar evolucion' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/evoluciones/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteEvolucion(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar evolucion' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== LABORATORIOS ==========
|
||||
app.get('/api/laboratorios', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllLaboratorios());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener laboratorios' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/laboratorios', async (req, res) => {
|
||||
try {
|
||||
const laboratorio = { ...req.body, id: generateUUID() };
|
||||
await createLaboratorio(laboratorio);
|
||||
res.json(laboratorio);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear laboratorio' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/laboratorios/:id', async (req, res) => {
|
||||
try {
|
||||
await updateLaboratorio(req.params.id, req.body);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar laboratorio' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/laboratorios/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteLaboratorio(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar laboratorio' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== ACIDOS BASE ==========
|
||||
app.get('/api/acid-os-base', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllAcidosBase());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener acidos base' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/acid-os-base', async (req, res) => {
|
||||
try {
|
||||
const acido = { ...req.body, id: generateUUID() };
|
||||
await createAcidoBase(acido);
|
||||
res.json(acido);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear acido base' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/acid-os-base/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteAcidoBase(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar acido base' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== CULTIVOS ==========
|
||||
app.get('/api/cultivos', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllCultivos());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener cultivos' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/cultivos', async (req, res) => {
|
||||
try {
|
||||
const cultivo = { ...req.body, id: generateUUID() };
|
||||
await createCultivo(cultivo);
|
||||
res.json(cultivo);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear cultivo' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/cultivos/:id', async (req, res) => {
|
||||
try {
|
||||
await updateCultivo(req.params.id, req.body);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar cultivo' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/cultivos/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteCultivo(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar cultivo' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== ESTUDIOS COMPLEMENTARIOS ==========
|
||||
app.get('/api/estudios-complementarios', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllEstudiosComplementarios());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener estudios' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/estudios-complementarios', async (req, res) => {
|
||||
try {
|
||||
const estudio = { ...req.body, id: generateUUID() };
|
||||
await createEstudioComplementario(estudio);
|
||||
res.json(estudio);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear estudio' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/estudios-complementarios/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteEstudioComplementario(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar estudio' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== INTERCONSULTAS ==========
|
||||
app.get('/api/interconsultas', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllInterconsultas());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener interconsultas' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/interconsultas', async (req, res) => {
|
||||
try {
|
||||
const interconsulta = { ...req.body, id: generateUUID() };
|
||||
await createInterconsulta(interconsulta);
|
||||
res.json(interconsulta);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear interconsulta' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/interconsultas/:id', async (req, res) => {
|
||||
try {
|
||||
await updateInterconsulta(req.params.id, req.body);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar interconsulta' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/interconsultas/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteInterconsulta(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar interconsulta' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== ATB ==========
|
||||
app.get('/api/atb', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllAtb());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener ATB' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/atb', async (req, res) => {
|
||||
try {
|
||||
const atb = { ...req.body, id: generateUUID() };
|
||||
await createAtb(atb);
|
||||
res.json(atb);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear ATB' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/atb/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteAtb(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar ATB' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== INDICACIONES ==========
|
||||
app.get('/api/indicaciones', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllIndicaciones());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener indicaciones' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/indicaciones', async (req, res) => {
|
||||
try {
|
||||
const indicacion = { ...req.body, id: generateUUID() };
|
||||
await createIndicacion(indicacion);
|
||||
res.json(indicacion);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear indicacion' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/indicaciones/:id', async (req, res) => {
|
||||
try {
|
||||
await updateIndicacion(req.params.id, req.body);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar indicacion' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/indicaciones/:id', async (req, res) => {
|
||||
try {
|
||||
await deleteIndicacion(req.params.id);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al eliminar indicacion' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== MOVIMIENTOS INDICACIONES ==========
|
||||
app.get('/api/movimientos-indicaciones', async (req, res) => {
|
||||
try {
|
||||
res.json(await getAllMovimientosIndicaciones());
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al obtener movimientos' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/movimientos-indicaciones', async (req, res) => {
|
||||
try {
|
||||
const movimiento = { ...req.body, id: generateUUID() };
|
||||
await createMovimientoIndicacion(movimiento);
|
||||
res.json(movimiento);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al crear movimiento' });
|
||||
}
|
||||
});
|
||||
|
||||
// ========== AUTH ==========
|
||||
app.post('/api/auth/login', async (req, res) => {
|
||||
try {
|
||||
const { dni, password } = req.body;
|
||||
if (!dni || !password) {
|
||||
return res.status(400).json({ error: 'DNI y contraseña requeridos' });
|
||||
}
|
||||
|
||||
const usuario = await getUsuarioByDni(dni);
|
||||
if (!usuario) {
|
||||
return res.status(401).json({ error: 'Usuario no encontrado' });
|
||||
}
|
||||
|
||||
const validPassword = verifyPassword(dni, password);
|
||||
if (!validPassword) {
|
||||
return res.status(401).json({ error: 'Contraseña incorrecta' });
|
||||
}
|
||||
|
||||
const { passwordHash, ...userWithoutPassword } = usuario;
|
||||
res.json(userWithoutPassword);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error en autenticación' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/auth/change-password', async (req, res) => {
|
||||
try {
|
||||
const { dni, oldPassword, newPassword } = req.body;
|
||||
if (!dni || !oldPassword || !newPassword) {
|
||||
return res.status(400).json({ error: 'Todos los campos son requeridos' });
|
||||
}
|
||||
|
||||
const validPassword = verifyPassword(dni, oldPassword);
|
||||
if (!validPassword) {
|
||||
return res.status(401).json({ error: 'Contraseña actual incorrecta' });
|
||||
}
|
||||
|
||||
const newHash = hashPassword(newPassword);
|
||||
const usuario = await getUsuarioByDni(dni);
|
||||
if (usuario) {
|
||||
await updateUsuario(usuario.id, { passwordHash: newHash });
|
||||
}
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al cambiar contraseña' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/auth/update-email', async (req, res) => {
|
||||
try {
|
||||
const { dni, newEmail } = req.body;
|
||||
if (!dni || !newEmail) {
|
||||
return res.status(400).json({ error: 'DNI y email son requeridos' });
|
||||
}
|
||||
|
||||
const usuario = await getUsuarioByDni(dni);
|
||||
if (usuario) {
|
||||
await updateUsuario(usuario.id, { email: newEmail });
|
||||
}
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: 'Error al actualizar email' });
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize DB and start server
|
||||
const PORT = process.env.PORT || 4000;
|
||||
const HOST = process.env.HOST || '0.0.0.0';
|
||||
|
||||
initDb().then(() => {
|
||||
app.listen(Number(PORT), HOST, () => {
|
||||
console.log(`MariaDB Server running on http://${HOST}:${PORT}`);
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error('Failed to initialize database:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,662 @@
|
||||
import mariadb from 'mariadb';
|
||||
import bcrypt from 'bcryptjs';
|
||||
|
||||
// MariaDB connection pool
|
||||
const pool = mariadb.createPool({
|
||||
host: process.env.DB_HOST || '10.9.8.135',
|
||||
port: parseInt(process.env.DB_PORT || '3306'),
|
||||
user: process.env.DB_USER || 'snlavaise',
|
||||
password: process.env.DB_PASSWORD || '1123581321Rtaylor%_+',
|
||||
database: process.env.DB_NAME || 'santojanni',
|
||||
connectionLimit: 10,
|
||||
connectTimeout: 10000,
|
||||
});
|
||||
|
||||
// Helper to execute queries
|
||||
async function query(sql, params = []) {
|
||||
let conn;
|
||||
try {
|
||||
conn = await pool.getConnection();
|
||||
const result = await conn.query(sql, params);
|
||||
return result;
|
||||
} finally {
|
||||
if (conn) conn.release();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to get a single row
|
||||
async function queryOne(sql, params = []) {
|
||||
const rows = await query(sql, params);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
// Initialize database tables
|
||||
export async function initDb() {
|
||||
const tables = [
|
||||
`CREATE TABLE IF NOT EXISTS usuarios (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
apellido VARCHAR(255) NOT NULL,
|
||||
nombre VARCHAR(255) NOT NULL,
|
||||
dni VARCHAR(20) NOT NULL UNIQUE,
|
||||
fechaNacimiento VARCHAR(10),
|
||||
email VARCHAR(255),
|
||||
rol VARCHAR(50),
|
||||
matriculaProfesional VARCHAR(100),
|
||||
passwordHash VARCHAR(255),
|
||||
areaId VARCHAR(36),
|
||||
fechaCreacion VARCHAR(10)
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS pacientes (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
apellido VARCHAR(255) NOT NULL,
|
||||
nombre VARCHAR(255) NOT NULL,
|
||||
dni VARCHAR(20) NOT NULL UNIQUE,
|
||||
fechaNacimiento VARCHAR(10),
|
||||
sexo VARCHAR(10),
|
||||
telefono VARCHAR(50),
|
||||
email VARCHAR(255),
|
||||
direccion TEXT,
|
||||
obraSocial VARCHAR(100),
|
||||
nacionalidad VARCHAR(100),
|
||||
medicacionHabitual TEXT,
|
||||
antecedentes TEXT,
|
||||
alergias TEXT,
|
||||
grupoSanguineo VARCHAR(10),
|
||||
historiaClinica TEXT
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS areas (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
nombre VARCHAR(255) NOT NULL UNIQUE
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS camas (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
numero VARCHAR(20) NOT NULL,
|
||||
areaId VARCHAR(36),
|
||||
tipo VARCHAR(50) DEFAULT 'Estándar',
|
||||
estado VARCHAR(20) DEFAULT 'Disponible',
|
||||
pacienteId VARCHAR(36),
|
||||
internacionId VARCHAR(36)
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS internaciones (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
pacienteId VARCHAR(36) NOT NULL,
|
||||
camaId VARCHAR(36),
|
||||
areaId VARCHAR(36),
|
||||
fechaIngresoHospital VARCHAR(10),
|
||||
fechaIngresoClinica VARCHAR(10),
|
||||
fechaEgreso VARCHAR(10),
|
||||
diagnosticoIngreso TEXT,
|
||||
motivoConsulta TEXT,
|
||||
enfermedadActual TEXT,
|
||||
antecedentesEnfermedadActual TEXT,
|
||||
diagnosticoEgreso TEXT,
|
||||
medicoIngresante VARCHAR(255),
|
||||
motivoEgreso VARCHAR(50),
|
||||
activa TINYINT DEFAULT 1,
|
||||
apache TEXT,
|
||||
derivacion TEXT
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS evoluciones (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
internacionId VARCHAR(36) NOT NULL,
|
||||
fecha VARCHAR(10) NOT NULL,
|
||||
hora VARCHAR(5),
|
||||
medico VARCHAR(255),
|
||||
signosVitales TEXT,
|
||||
examenFisico TEXT,
|
||||
novedades TEXT,
|
||||
comentarios TEXT,
|
||||
pendientes TEXT
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS laboratorios (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
pacienteId VARCHAR(36) NOT NULL,
|
||||
internacionId VARCHAR(36),
|
||||
fecha VARCHAR(10) NOT NULL,
|
||||
hora VARCHAR(5),
|
||||
tipo VARCHAR(50),
|
||||
resultados TEXT,
|
||||
observaciones TEXT,
|
||||
medicoSolicitante VARCHAR(255)
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS acidosbase (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
pacienteId VARCHAR(36) NOT NULL,
|
||||
internacionId VARCHAR(36),
|
||||
fecha VARCHAR(10) NOT NULL,
|
||||
hora VARCHAR(5),
|
||||
ph DECIMAL(4,2),
|
||||
pco2 DECIMAL(6,2),
|
||||
po2 DECIMAL(6,2),
|
||||
hco3 DECIMAL(6,2),
|
||||
be DECIMAL(6,2),
|
||||
sato2 DECIMAL(6,2),
|
||||
lactato DECIMAL(6,2),
|
||||
interpretacion TEXT,
|
||||
fio2 DECIMAL(6,2)
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS cultivos (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
pacienteId VARCHAR(36) NOT NULL,
|
||||
internacionId VARCHAR(36),
|
||||
fechaToma VARCHAR(10),
|
||||
protocolo VARCHAR(50),
|
||||
fechaResultado VARCHAR(10),
|
||||
tipoMuestra VARCHAR(100),
|
||||
germen TEXT,
|
||||
sensible TEXT,
|
||||
resistente TEXT,
|
||||
estado VARCHAR(50) DEFAULT 'NAF/Pendiente',
|
||||
observaciones TEXT
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS estudiosComplementarios (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
pacienteId VARCHAR(36) NOT NULL,
|
||||
internacionId VARCHAR(36),
|
||||
fecha VARCHAR(10),
|
||||
tipo VARCHAR(100),
|
||||
resultado TEXT
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS interconsultas (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
pacienteId VARCHAR(36) NOT NULL,
|
||||
internacionId VARCHAR(36) NOT NULL,
|
||||
fecha VARCHAR(10),
|
||||
servicioInterconsultado VARCHAR(255),
|
||||
motivo TEXT,
|
||||
respuestaInterconsulta TEXT,
|
||||
respuestaFecha VARCHAR(10)
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS atb (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
pacienteId VARCHAR(36) NOT NULL,
|
||||
internacionId VARCHAR(36) NOT NULL,
|
||||
antibiotico VARCHAR(255),
|
||||
fechaInicio VARCHAR(10),
|
||||
fechaFinalizacion VARCHAR(10)
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS indicaciones (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
internacionId VARCHAR(36) NOT NULL,
|
||||
tipo VARCHAR(50) NOT NULL,
|
||||
droga VARCHAR(255),
|
||||
dosis VARCHAR(100),
|
||||
frecuenciaHoras INT,
|
||||
via VARCHAR(50),
|
||||
descripcion TEXT,
|
||||
tipoPlan VARCHAR(50),
|
||||
tipoPlan2 VARCHAR(50),
|
||||
cantidadMl INT,
|
||||
cantidadMl2 INT,
|
||||
tiempoHoras INT,
|
||||
estado VARCHAR(20) DEFAULT 'Activa',
|
||||
medicoCrea VARCHAR(255),
|
||||
fechaCrea VARCHAR(10),
|
||||
tipoInsulina VARCHAR(50),
|
||||
unidadesDesayuno INT,
|
||||
unidadesAlmuerzo INT,
|
||||
unidadesNoche INT,
|
||||
indicacionNoFco TEXT
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS movimientos_indicaciones (
|
||||
id VARCHAR(36) PRIMARY KEY,
|
||||
indicacionId VARCHAR(36) NOT NULL,
|
||||
internacionId VARCHAR(36) NOT NULL,
|
||||
tipo VARCHAR(50) NOT NULL,
|
||||
fecha VARCHAR(10) NOT NULL,
|
||||
profesional VARCHAR(255) NOT NULL,
|
||||
indicacionPrevia TEXT,
|
||||
indicacionNueva TEXT
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS kv (
|
||||
kv_key VARCHAR(255) PRIMARY KEY,
|
||||
value TEXT
|
||||
)`
|
||||
];
|
||||
|
||||
for (const sql of tables) {
|
||||
await query(sql);
|
||||
}
|
||||
console.log('Database tables initialized');
|
||||
}
|
||||
|
||||
// ========== USUARIOS ==========
|
||||
export async function getUsuarioByDni(dni) {
|
||||
return await queryOne('SELECT * FROM usuarios WHERE dni = ?', [dni]);
|
||||
}
|
||||
|
||||
export async function getUsuarioById(id) {
|
||||
return await queryOne('SELECT * FROM usuarios WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
export async function getAllUsuarios() {
|
||||
return await query('SELECT * FROM usuarios ORDER BY apellido, nombre');
|
||||
}
|
||||
|
||||
export async function createUsuario(usuario) {
|
||||
await query(
|
||||
`INSERT INTO usuarios (id, apellido, nombre, dni, fechaNacimiento, email, rol, matriculaProfesional, passwordHash, areaId, fechaCreacion)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[usuario.id, usuario.apellido, usuario.nombre, usuario.dni, usuario.fechaNacimiento, usuario.email, usuario.rol, usuario.matriculaProfesional || null, usuario.passwordHash, usuario.areaId || null, usuario.fechaCreacion]
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateUsuario(id, datos) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (datos.apellido !== undefined) { fields.push('apellido = ?'); values.push(datos.apellido); }
|
||||
if (datos.nombre !== undefined) { fields.push('nombre = ?'); values.push(datos.nombre); }
|
||||
if (datos.fechaNacimiento !== undefined) { fields.push('fechaNacimiento = ?'); values.push(datos.fechaNacimiento); }
|
||||
if (datos.email !== undefined) { fields.push('email = ?'); values.push(datos.email); }
|
||||
if (datos.rol !== undefined) { fields.push('rol = ?'); values.push(datos.rol); }
|
||||
if (datos.matriculaProfesional !== undefined) { fields.push('matriculaProfesional = ?'); values.push(datos.matriculaProfesional); }
|
||||
if (datos.passwordHash !== undefined) { fields.push('passwordHash = ?'); values.push(datos.passwordHash); }
|
||||
if (datos.areaId !== undefined) { fields.push('areaId = ?'); values.push(datos.areaId); }
|
||||
|
||||
if (fields.length > 0) {
|
||||
values.push(id);
|
||||
await query(`UPDATE usuarios SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteUsuario(id) {
|
||||
await query('DELETE FROM usuarios WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
export async function verifyPassword(dni, password) {
|
||||
const row = await queryOne('SELECT passwordHash FROM usuarios WHERE dni = ?', [dni]);
|
||||
if (!row) return false;
|
||||
return bcrypt.compareSync(password, row.passwordHash);
|
||||
}
|
||||
|
||||
export function hashPassword(password) {
|
||||
return bcrypt.hashSync(password, 10);
|
||||
}
|
||||
|
||||
// ========== PACIENTES ==========
|
||||
export async function getAllPacientes() {
|
||||
return await query('SELECT * FROM pacientes');
|
||||
}
|
||||
|
||||
export async function getPacienteById(id) {
|
||||
return await queryOne('SELECT * FROM pacientes WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
export async function createPaciente(paciente) {
|
||||
await query(
|
||||
`INSERT INTO pacientes (id, apellido, nombre, dni, fechaNacimiento, sexo, telefono, email, direccion, obraSocial, nacionalidad, medicacionHabitual, antecedentes, alergias, grupoSanguineo, historiaClinica)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[paciente.id, paciente.apellido, paciente.nombre, paciente.dni, paciente.fechaNacimiento || null, paciente.sexo || null, paciente.telefono || null, paciente.email || null, paciente.direccion || null, paciente.obraSocial || null, paciente.nacionalidad || null, paciente.medicacionHabitual || null, paciente.antecedentes || null, paciente.alergias || null, paciente.grupoSanguineo || null, paciente.historiaClinica || null]
|
||||
);
|
||||
}
|
||||
|
||||
export async function updatePaciente(id, datos) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (datos.apellido !== undefined) { fields.push('apellido = ?'); values.push(datos.apellido); }
|
||||
if (datos.nombre !== undefined) { fields.push('nombre = ?'); values.push(datos.nombre); }
|
||||
if (datos.dni !== undefined) { fields.push('dni = ?'); values.push(datos.dni); }
|
||||
if (datos.fechaNacimiento !== undefined) { fields.push('fechaNacimiento = ?'); values.push(datos.fechaNacimiento); }
|
||||
if (datos.sexo !== undefined) { fields.push('sexo = ?'); values.push(datos.sexo); }
|
||||
if (datos.telefono !== undefined) { fields.push('telefono = ?'); values.push(datos.telefono); }
|
||||
if (datos.email !== undefined) { fields.push('email = ?'); values.push(datos.email); }
|
||||
if (datos.direccion !== undefined) { fields.push('direccion = ?'); values.push(datos.direccion); }
|
||||
if (datos.obraSocial !== undefined) { fields.push('obraSocial = ?'); values.push(datos.obraSocial); }
|
||||
if (datos.nacionalidad !== undefined) { fields.push('nacionalidad = ?'); values.push(datos.nacionalidad); }
|
||||
if (datos.medicacionHabitual !== undefined) { fields.push('medicacionHabitual = ?'); values.push(datos.medicacionHabitual); }
|
||||
if (datos.antecedentes !== undefined) { fields.push('antecedentes = ?'); values.push(datos.antecedentes); }
|
||||
if (datos.alergias !== undefined) { fields.push('alergias = ?'); values.push(datos.alergias); }
|
||||
if (datos.grupoSanguineo !== undefined) { fields.push('grupoSanguineo = ?'); values.push(datos.grupoSanguineo); }
|
||||
if (datos.historiaClinica !== undefined) { fields.push('historiaClinica = ?'); values.push(datos.historiaClinica); }
|
||||
|
||||
if (fields.length > 0) {
|
||||
values.push(id);
|
||||
await query(`UPDATE pacientes SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deletePaciente(id) {
|
||||
await query('DELETE FROM pacientes WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== AREAS ==========
|
||||
export async function getAllAreas() {
|
||||
return await query('SELECT * FROM areas');
|
||||
}
|
||||
|
||||
export async function createArea(area) {
|
||||
await query('INSERT INTO areas (id, nombre) VALUES (?, ?)', [area.id, area.nombre]);
|
||||
}
|
||||
|
||||
export async function updateArea(id, datos) {
|
||||
if (datos.nombre !== undefined) {
|
||||
await query('UPDATE areas SET nombre = ? WHERE id = ?', [datos.nombre, id]);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteArea(id) {
|
||||
await query('DELETE FROM areas WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== CAMAS ==========
|
||||
export async function getAllCamas() {
|
||||
return await query('SELECT * FROM camas');
|
||||
}
|
||||
|
||||
export async function getCamaById(id) {
|
||||
return await queryOne('SELECT * FROM camas WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
export async function createCama(cama) {
|
||||
await query(
|
||||
'INSERT INTO camas (id, numero, areaId, tipo, estado) VALUES (?, ?, ?, ?, ?)',
|
||||
[cama.id, cama.numero, cama.areaId, cama.tipo, cama.estado]
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateCama(id, updates) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (updates.numero !== undefined) { fields.push('numero = ?'); values.push(updates.numero); }
|
||||
if (updates.areaId !== undefined) { fields.push('areaId = ?'); values.push(updates.areaId); }
|
||||
if (updates.tipo !== undefined) { fields.push('tipo = ?'); values.push(updates.tipo); }
|
||||
if (updates.estado !== undefined) { fields.push('estado = ?'); values.push(updates.estado); }
|
||||
if (updates.pacienteId !== undefined) { fields.push('pacienteId = ?'); values.push(updates.pacienteId); }
|
||||
if (updates.internacionId !== undefined) { fields.push('internacionId = ?'); values.push(updates.internacionId); }
|
||||
|
||||
if (fields.length > 0) {
|
||||
values.push(id);
|
||||
await query(`UPDATE camas SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteCama(id) {
|
||||
await query('DELETE FROM camas WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== INTERNACIONES ==========
|
||||
export async function getAllInternaciones() {
|
||||
const rows = await query('SELECT * FROM internaciones');
|
||||
return rows.map(r => ({ ...r, activa: !!r.activa }));
|
||||
}
|
||||
|
||||
export async function getInternacionById(id) {
|
||||
const row = await queryOne('SELECT * FROM internaciones WHERE id = ?', [id]);
|
||||
if (row) row.activa = !!row.activa;
|
||||
return row;
|
||||
}
|
||||
|
||||
export async function createInternacion(internacion) {
|
||||
await query(
|
||||
`INSERT INTO internaciones (id, pacienteId, camaId, areaId, fechaIngresoHospital, fechaIngresoClinica, fechaEgreso, diagnosticoIngreso, motivoConsulta, enfermedadActual, antecedentesEnfermedadActual, diagnosticoEgreso, medicoIngresante, motivoEgreso, activa, apache, derivacion)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[internacion.id, internacion.pacienteId, internacion.camaId, internacion.areaId || null, internacion.fechaIngresoHospital || null, internacion.fechaIngresoClinica || null, internacion.fechaEgreso || null, internacion.diagnosticoIngreso || null, internacion.motivoConsulta || null, internacion.enfermedadActual || null, internacion.antecedentesEnfermedadActual || null, internacion.diagnosticoEgreso || null, internacion.medicoIngresante || null, internacion.motivoEgreso || null, internacion.activa ? 1 : 0, internacion.apache || null, internacion.derivacion || null]
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateInternacion(id, datos) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (datos.pacienteId !== undefined) { fields.push('pacienteId = ?'); values.push(datos.pacienteId); }
|
||||
if (datos.camaId !== undefined) { fields.push('camaId = ?'); values.push(datos.camaId); }
|
||||
if (datos.areaId !== undefined) { fields.push('areaId = ?'); values.push(datos.areaId); }
|
||||
if (datos.fechaIngresoHospital !== undefined) { fields.push('fechaIngresoHospital = ?'); values.push(datos.fechaIngresoHospital); }
|
||||
if (datos.fechaIngresoClinica !== undefined) { fields.push('fechaIngresoClinica = ?'); values.push(datos.fechaIngresoClinica); }
|
||||
if (datos.fechaEgreso !== undefined) { fields.push('fechaEgreso = ?'); values.push(datos.fechaEgreso); }
|
||||
if (datos.diagnosticoIngreso !== undefined) { fields.push('diagnosticoIngreso = ?'); values.push(datos.diagnosticoIngreso); }
|
||||
if (datos.motivoConsulta !== undefined) { fields.push('motivoConsulta = ?'); values.push(datos.motivoConsulta); }
|
||||
if (datos.enfermedadActual !== undefined) { fields.push('enfermedadActual = ?'); values.push(datos.enfermedadActual); }
|
||||
if (datos.antecedentesEnfermedadActual !== undefined) { fields.push('antecedentesEnfermedadActual = ?'); values.push(datos.antecedentesEnfermedadActual); }
|
||||
if (datos.diagnosticoEgreso !== undefined) { fields.push('diagnosticoEgreso = ?'); values.push(datos.diagnosticoEgreso); }
|
||||
if (datos.medicoIngresante !== undefined) { fields.push('medicoIngresante = ?'); values.push(datos.medicoIngresante); }
|
||||
if (datos.motivoEgreso !== undefined) { fields.push('motivoEgreso = ?'); values.push(datos.motivoEgreso); }
|
||||
if (datos.activa !== undefined) { fields.push('activa = ?'); values.push(datos.activa ? 1 : 0); }
|
||||
if (datos.apache !== undefined) { fields.push('apache = ?'); values.push(datos.apache); }
|
||||
if (datos.derivacion !== undefined) { fields.push('derivacion = ?'); values.push(datos.derivacion); }
|
||||
|
||||
if (fields.length > 0) {
|
||||
values.push(id);
|
||||
await query(`UPDATE internaciones SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteInternacion(id) {
|
||||
await query('DELETE FROM internaciones WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== EVOLUCIONES ==========
|
||||
export async function getAllEvoluciones() {
|
||||
return await query('SELECT * FROM evoluciones');
|
||||
}
|
||||
|
||||
export async function createEvolucion(evolucion) {
|
||||
await query(
|
||||
'INSERT INTO evoluciones (id, internacionId, fecha, hora, medico, signosVitales, examenFisico, novedades, comentarios, pendientes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[evolucion.id, evolucion.internacionId, evolucion.fecha, evolucion.hora || '', evolucion.medico || '', JSON.stringify(evolucion.signosVitales || {}), JSON.stringify(evolucion.examenFisico || {}), evolucion.novedades || '', evolucion.comentarios || '', evolucion.pendientes || '']
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateEvolucion(id, datos) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (datos.internacionId !== undefined) { fields.push('internacionId = ?'); values.push(datos.internacionId); }
|
||||
if (datos.fecha !== undefined) { fields.push('fecha = ?'); values.push(datos.fecha); }
|
||||
if (datos.hora !== undefined) { fields.push('hora = ?'); values.push(datos.hora); }
|
||||
if (datos.medico !== undefined) { fields.push('medico = ?'); values.push(datos.medico); }
|
||||
if (datos.signosVitales !== undefined) { fields.push('signosVitales = ?'); values.push(JSON.stringify(datos.signosVitales)); }
|
||||
if (datos.examenFisico !== undefined) { fields.push('examenFisico = ?'); values.push(JSON.stringify(datos.examenFisico)); }
|
||||
if (datos.novedades !== undefined) { fields.push('novedades = ?'); values.push(datos.novedades); }
|
||||
if (datos.comentarios !== undefined) { fields.push('comentarios = ?'); values.push(datos.comentarios); }
|
||||
if (datos.pendientes !== undefined) { fields.push('pendientes = ?'); values.push(datos.pendientes); }
|
||||
|
||||
if (fields.length > 0) {
|
||||
values.push(id);
|
||||
await query(`UPDATE evoluciones SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteEvolucion(id) {
|
||||
await query('DELETE FROM evoluciones WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== LABORATORIOS ==========
|
||||
export async function getAllLaboratorios() {
|
||||
return await query('SELECT * FROM laboratorios');
|
||||
}
|
||||
|
||||
export async function createLaboratorio(laboratorio) {
|
||||
await query(
|
||||
'INSERT INTO laboratorios (id, pacienteId, internacionId, fecha, hora, tipo, resultados, observaciones, medicoSolicitante) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[laboratorio.id, laboratorio.pacienteId, laboratorio.internacionId || null, laboratorio.fecha, laboratorio.hora || null, laboratorio.tipo, JSON.stringify(laboratorio.resultados), laboratorio.observaciones || null, laboratorio.medicoSolicitante || null]
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateLaboratorio(id, datos) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (datos.pacienteId !== undefined) { fields.push('pacienteId = ?'); values.push(datos.pacienteId); }
|
||||
if (datos.internacionId !== undefined) { fields.push('internacionId = ?'); values.push(datos.internacionId); }
|
||||
if (datos.fecha !== undefined) { fields.push('fecha = ?'); values.push(datos.fecha); }
|
||||
if (datos.hora !== undefined) { fields.push('hora = ?'); values.push(datos.hora); }
|
||||
if (datos.tipo !== undefined) { fields.push('tipo = ?'); values.push(datos.tipo); }
|
||||
if (datos.resultados !== undefined) { fields.push('resultados = ?'); values.push(JSON.stringify(datos.resultados)); }
|
||||
if (datos.observaciones !== undefined) { fields.push('observaciones = ?'); values.push(datos.observaciones); }
|
||||
if (datos.medicoSolicitante !== undefined) { fields.push('medicoSolicitante = ?'); values.push(datos.medicoSolicitante); }
|
||||
|
||||
if (fields.length > 0) {
|
||||
values.push(id);
|
||||
await query(`UPDATE laboratorios SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteLaboratorio(id) {
|
||||
await query('DELETE FROM laboratorios WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== ACIDOS BASE ==========
|
||||
export async function getAllAcidosBase() {
|
||||
return await query('SELECT * FROM acidosbase');
|
||||
}
|
||||
|
||||
export async function createAcidoBase(acido) {
|
||||
await query(
|
||||
'INSERT INTO acidosbase (id, pacienteId, internacionId, fecha, hora, ph, pco2, po2, hco3, be, sato2, lactato, interpretacion, fio2) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[acido.id, acido.pacienteId, acido.internacionId || null, acido.fecha, acido.hora || null, acido.ph || null, acido.pco2 || null, acido.po2 || null, acido.hco3 || null, acido.be || null, acido.sato2 || null, acido.lactato || null, acido.interpretacion || null, acido.fio2 || null]
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteAcidoBase(id) {
|
||||
await query('DELETE FROM acidosbase WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== CULTIVOS ==========
|
||||
export async function getAllCultivos() {
|
||||
return await query('SELECT * FROM cultivos');
|
||||
}
|
||||
|
||||
export async function createCultivo(cultivo) {
|
||||
await query(
|
||||
'INSERT INTO cultivos (id, pacienteId, internacionId, fechaToma, protocolo, fechaResultado, tipoMuestra, germen, sensible, resistente, estado, observaciones) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[cultivo.id, cultivo.pacienteId, cultivo.internacionId, cultivo.fechaToma || null, cultivo.protocolo || null, cultivo.fechaResultado || null, cultivo.tipoMuestra || null, cultivo.germen || null, cultivo.sensible || null, cultivo.resistente || null, cultivo.estado || 'NAF/Pendiente', cultivo.observaciones || null]
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateCultivo(id, datos) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (datos.estado !== undefined) { fields.push('estado = ?'); values.push(datos.estado); }
|
||||
if (datos.germen !== undefined) { fields.push('germen = ?'); values.push(datos.germen); }
|
||||
if (datos.sensible !== undefined) { fields.push('sensible = ?'); values.push(datos.sensible); }
|
||||
if (datos.resistente !== undefined) { fields.push('resistente = ?'); values.push(datos.resistente); }
|
||||
if (datos.fechaResultado !== undefined) { fields.push('fechaResultado = ?'); values.push(datos.fechaResultado); }
|
||||
|
||||
if (fields.length > 0) {
|
||||
values.push(id);
|
||||
await query(`UPDATE cultivos SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteCultivo(id) {
|
||||
await query('DELETE FROM cultivos WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== ESTUDIOS COMPLEMENTARIOS ==========
|
||||
export async function getAllEstudiosComplementarios() {
|
||||
return await query('SELECT * FROM estudiosComplementarios');
|
||||
}
|
||||
|
||||
export async function createEstudioComplementario(estudio) {
|
||||
await query(
|
||||
'INSERT INTO estudiosComplementarios (id, pacienteId, internacionId, fecha, tipo, resultado) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[estudio.id, estudio.pacienteId, estudio.internacionId || null, estudio.fecha, estudio.tipo, estudio.resultado]
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteEstudioComplementario(id) {
|
||||
await query('DELETE FROM estudiosComplementarios WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== INTERCONSULTAS ==========
|
||||
export async function getAllInterconsultas() {
|
||||
return await query('SELECT * FROM interconsultas');
|
||||
}
|
||||
|
||||
export async function createInterconsulta(interconsulta) {
|
||||
await query(
|
||||
'INSERT INTO interconsultas (id, pacienteId, internacionId, fecha, servicioInterconsultado, motivo, respuestaInterconsulta, respuestaFecha) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[interconsulta.id, interconsulta.pacienteId, interconsulta.internacionId, interconsulta.fecha, interconsulta.servicioInterconsultado, interconsulta.motivo || null, interconsulta.respuestaInterconsulta || null, interconsulta.respuestaFecha || null]
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateInterconsulta(id, datos) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (datos.respuestaInterconsulta !== undefined) { fields.push('respuestaInterconsulta = ?'); values.push(datos.respuestaInterconsulta); }
|
||||
if (datos.respuestaFecha !== undefined) { fields.push('respuestaFecha = ?'); values.push(datos.respuestaFecha); }
|
||||
|
||||
if (fields.length > 0) {
|
||||
values.push(id);
|
||||
await query(`UPDATE interconsultas SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteInterconsulta(id) {
|
||||
await query('DELETE FROM interconsultas WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== ATB ==========
|
||||
export async function getAllAtb() {
|
||||
return await query('SELECT * FROM atb');
|
||||
}
|
||||
|
||||
export async function createAtb(atb) {
|
||||
await query(
|
||||
'INSERT INTO atb (id, pacienteId, internacionId, antibiotico, fechaInicio, fechaFinalizacion) VALUES (?, ?, ?, ?, ?, ?)',
|
||||
[atb.id, atb.pacienteId, atb.internacionId, atb.antibiotico, atb.fechaInicio, atb.fechaFinalizacion || null]
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteAtb(id) {
|
||||
await query('DELETE FROM atb WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== INDICACIONES ==========
|
||||
export async function getAllIndicaciones() {
|
||||
return await query('SELECT * FROM indicaciones');
|
||||
}
|
||||
|
||||
export async function createIndicacion(indicacion) {
|
||||
await query(
|
||||
'INSERT INTO indicaciones (id, internacionId, tipo, droga, dosis, frecuenciaHoras, via, tipoPlan, tipoPlan2, cantidadMl, cantidadMl2, tiempoHoras, estado, medicoCrea, fechaCrea, tipoInsulina, unidadesDesayuno, unidadesAlmuerzo, unidadesNoche, indicacionNoFco) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[indicacion.id, indicacion.internacionId, indicacion.tipo, indicacion.droga || null, indicacion.dosis || null, indicacion.frecuenciaHoras || null, indicacion.via || null, indicacion.tipoPlan || null, indicacion.tipoPlan2 || null, indicacion.cantidadMl || null, indicacion.cantidadMl2 || null, indicacion.tiempoHoras || null, indicacion.estado, indicacion.medicoCrea, indicacion.fechaCrea, indicacion.tipoInsulina || null, indicacion.unidadesDesayuno || null, indicacion.unidadesAlmuerzo || null, indicacion.unidadesNoche || null, indicacion.indicacionNoFco || null]
|
||||
);
|
||||
}
|
||||
|
||||
export async function updateIndicacion(id, datos) {
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (datos.estado !== undefined) { fields.push('estado = ?'); values.push(datos.estado); }
|
||||
|
||||
if (fields.length > 0) {
|
||||
values.push(id);
|
||||
await query(`UPDATE indicaciones SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteIndicacion(id) {
|
||||
await query('DELETE FROM indicaciones WHERE id = ?', [id]);
|
||||
}
|
||||
|
||||
// ========== MOVIMIENTOS INDICACIONES ==========
|
||||
export async function getAllMovimientosIndicaciones() {
|
||||
return await query('SELECT * FROM movimientos_indicaciones');
|
||||
}
|
||||
|
||||
export async function createMovimientoIndicacion(movimiento) {
|
||||
await query(
|
||||
'INSERT INTO movimientos_indicaciones (id, indicacionId, internacionId, tipo, fecha, profesional, indicacionPrevia, indicacionNueva) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[movimiento.id, movimiento.indicacionId, movimiento.internacionId, movimiento.tipo, movimiento.fecha, movimiento.profesional, movimiento.indicacionPrevia || null, movimiento.indicacionNueva || null]
|
||||
);
|
||||
}
|
||||
|
||||
// ========== KV STORE ==========
|
||||
export async function getValue(key) {
|
||||
const row = await queryOne('SELECT value FROM kv WHERE kv_key = ?', [key]);
|
||||
return row?.value ?? null;
|
||||
}
|
||||
|
||||
export async function setValue(key, value) {
|
||||
await query(
|
||||
'INSERT INTO kv (kv_key, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value = VALUES(value)',
|
||||
[key, value]
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import mariadb from 'mariadb';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const SQLITE_PATH = join(__dirname, 'data', 'hospital.db');
|
||||
|
||||
// MariaDB connection config
|
||||
const mariaPool = mariadb.createPool({
|
||||
host: process.env.DB_HOST || '10.9.8.135',
|
||||
port: parseInt(process.env.DB_PORT || '3306'),
|
||||
user: process.env.DB_USER || 'snlavaise',
|
||||
password: process.env.DB_PASSWORD || '1123581321Rtaylor%_+',
|
||||
database: process.env.DB_NAME || 'santojanni',
|
||||
connectionLimit: 5,
|
||||
});
|
||||
|
||||
async function migrate() {
|
||||
console.log('Starting migration from SQLite to MariaDB...');
|
||||
|
||||
// Open SQLite database
|
||||
const sqliteDb = new Database(SQLITE_PATH);
|
||||
console.log('Connected to SQLite database');
|
||||
|
||||
const mariaConn = await mariaPool.getConnection();
|
||||
console.log('Connected to MariaDB');
|
||||
|
||||
try {
|
||||
// Migrate each table
|
||||
const tables = [
|
||||
'usuarios', 'pacientes', 'areas', 'camas', 'internaciones',
|
||||
'evoluciones', 'laboratorios', 'acidosbase', 'cultivos',
|
||||
'estudiosComplementarios', 'interconsultas', 'atb',
|
||||
'indicaciones', 'movimientos_indicaciones', 'kv'
|
||||
];
|
||||
|
||||
for (const table of tables) {
|
||||
console.log(`Migrating ${table}...`);
|
||||
|
||||
// Get all data from SQLite
|
||||
const rows = sqliteDb.prepare(`SELECT * FROM ${table}`).all();
|
||||
console.log(` Found ${rows.length} rows in ${table}`);
|
||||
|
||||
if (rows.length === 0) continue;
|
||||
|
||||
// Get column names from first row
|
||||
const columns = Object.keys(rows[0]);
|
||||
const placeholders = columns.map(() => '?').join(', ');
|
||||
const columnNames = columns.map(c => `\`${c}\``).join(', ');
|
||||
|
||||
// Insert into MariaDB
|
||||
for (const row of rows) {
|
||||
const values = columns.map(col => {
|
||||
const val = row[col];
|
||||
// Handle JSON strings or special cases
|
||||
if (typeof val === 'object' && val !== null) {
|
||||
return JSON.stringify(val);
|
||||
}
|
||||
return val;
|
||||
});
|
||||
|
||||
try {
|
||||
await mariaConn.query(
|
||||
`INSERT IGNORE INTO ${table} (${columnNames}) VALUES (${placeholders})`,
|
||||
values
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(` Error inserting row in ${table}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(` Migrated ${rows.length} rows to ${table}`);
|
||||
}
|
||||
|
||||
console.log('Migration completed successfully!');
|
||||
} catch (err) {
|
||||
console.error('Migration failed:', err);
|
||||
} finally {
|
||||
sqliteDb.close();
|
||||
mariaConn.release();
|
||||
mariaPool.end();
|
||||
}
|
||||
}
|
||||
|
||||
migrate();
|
||||
Reference in New Issue
Block a user