- Migrar de sqlite3 a better-sqlite3 con conexión persistente - Configurar WAL mode, busy_timeout y PRAGMAs optimizados - Implementar transacciones para operaciones bulk - Corregir error initialLoadComplete en useHospitalStore.ts - Agregar tablas usuarios y kv faltantes - Actualizar .gitignore para archivos WAL de SQLite
213 lines
6.4 KiB
JavaScript
213 lines
6.4 KiB
JavaScript
import Database from 'better-sqlite3';
|
|
import { dirname } from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
import bcrypt from 'bcryptjs';
|
|
import { existsSync, mkdirSync } from 'fs';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const DB_PATH = __dirname + '/data/hospital.db';
|
|
|
|
// Ensure data directory exists
|
|
if (!existsSync(__dirname + '/data')) {
|
|
mkdirSync(__dirname + '/data', { recursive: true });
|
|
}
|
|
|
|
// Create persistent database connection with WAL mode and proper settings
|
|
const db = new Database(DB_PATH);
|
|
|
|
// Enable WAL mode for better concurrency
|
|
db.pragma('journal_mode = WAL');
|
|
|
|
// Set busy timeout to 5000ms (5 seconds)
|
|
db.pragma('busy_timeout = 5000');
|
|
|
|
// Additional performance and concurrency settings
|
|
db.pragma('synchronous = NORMAL');
|
|
db.pragma('cache_size = 1000');
|
|
db.pragma('temp_store = MEMORY');
|
|
db.pragma('mmap_size = 268435456'); // 256MB
|
|
|
|
export function getDb() {
|
|
return db;
|
|
}
|
|
|
|
function rowToObj(row) {
|
|
if (!row) return row;
|
|
const obj = {};
|
|
for (const key in row) {
|
|
const val = row[key];
|
|
try {
|
|
obj[key] = typeof val === 'string' && (val.startsWith('[') || val.startsWith('{')) ? JSON.parse(val) : val;
|
|
} catch {
|
|
obj[key] = val;
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
export function getValue(key) {
|
|
const row = db.prepare('SELECT value FROM kv WHERE key = ?').get(key);
|
|
return row?.value ?? null;
|
|
}
|
|
|
|
export function setValue(key, value) {
|
|
const stmt = db.prepare('INSERT INTO kv (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value');
|
|
stmt.run(key, value);
|
|
}
|
|
|
|
export function getUsuarioByDni(dni) {
|
|
const row = db.prepare('SELECT * FROM usuarios WHERE dni = ?').get(dni);
|
|
return row || null;
|
|
}
|
|
|
|
export function getUsuarioById(id) {
|
|
const row = db.prepare('SELECT * FROM usuarios WHERE id = ?').get(id);
|
|
return row || null;
|
|
}
|
|
|
|
export function getAllUsuarios() {
|
|
const rows = db.prepare('SELECT * FROM usuarios ORDER BY apellido, nombre').all();
|
|
return rows;
|
|
}
|
|
|
|
export function createUsuario(usuario) {
|
|
const stmt = db.prepare(`INSERT INTO usuarios (id, apellido, nombre, dni, fechaNacimiento, email, rol, matriculaProfesional, passwordHash, areaId, fechaCreacion)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
stmt.run(
|
|
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 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);
|
|
db.prepare(`UPDATE usuarios SET ${fields.join(', ')} WHERE id = ?`).run(values);
|
|
}
|
|
}
|
|
|
|
export function deleteUsuario(id) {
|
|
db.prepare('DELETE FROM usuarios WHERE id = ?').run(id);
|
|
}
|
|
|
|
export function verifyPassword(dni, password) {
|
|
const row = db.prepare('SELECT passwordHash FROM usuarios WHERE dni = ?').get(dni);
|
|
if (!row) return false;
|
|
return bcrypt.compareSync(password, row.passwordHash);
|
|
}
|
|
|
|
export function hashPassword(password) {
|
|
return bcrypt.hashSync(password, 10);
|
|
}
|
|
|
|
export function getAllPacientes() {
|
|
const rows = db.prepare('SELECT * FROM pacientes').all();
|
|
return rows;
|
|
}
|
|
|
|
export function getAllAreas() {
|
|
const rows = db.prepare('SELECT * FROM areas').all();
|
|
return rows;
|
|
}
|
|
|
|
export function getAllCamas() {
|
|
const rows = db.prepare('SELECT * FROM camas').all();
|
|
return rows;
|
|
}
|
|
|
|
export function updateCama(id, updates) {
|
|
const fields = [];
|
|
const values = [];
|
|
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);
|
|
db.prepare(`UPDATE camas SET ${fields.join(', ')} WHERE id = ?`).run(values);
|
|
}
|
|
}
|
|
|
|
export function getAllInternaciones() {
|
|
const rows = db.prepare('SELECT * FROM internaciones').all();
|
|
return rows.map(i => ({ ...i, activa: !!i.activa }));
|
|
}
|
|
|
|
export function getAllEvoluciones() {
|
|
const rows = db.prepare('SELECT * FROM evoluciones').all();
|
|
return rows.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
|
|
}));
|
|
}
|
|
|
|
export function getAllLaboratorios() {
|
|
const rows = db.prepare('SELECT * FROM laboratorios').all();
|
|
return rows.map(l => ({ ...l, resultados: typeof l.resultados === 'string' ? JSON.parse(l.resultados) : l.resultados }));
|
|
}
|
|
|
|
export function getAllAcidosBase() {
|
|
const rows = db.prepare('SELECT * FROM acidosbase').all();
|
|
return rows;
|
|
}
|
|
|
|
export function getAllCultivos() {
|
|
const rows = db.prepare('SELECT * FROM cultivos').all();
|
|
return rows;
|
|
}
|
|
|
|
export function getAllEstudiosComplementarios() {
|
|
const rows = db.prepare('SELECT * FROM estudiosComplementarios').all();
|
|
return rows;
|
|
}
|
|
|
|
export function getAllInterconsultas() {
|
|
const rows = db.prepare('SELECT * FROM interconsultas').all();
|
|
return rows.map(ic => ({ ...ic, realizada: !!ic.realizada }));
|
|
}
|
|
|
|
export function getAllAtb() {
|
|
const rows = db.prepare('SELECT * FROM atb').all();
|
|
return rows;
|
|
}
|
|
|
|
export function getAllIndicaciones() {
|
|
const rows = db.prepare('SELECT * FROM indicaciones').all();
|
|
return rows;
|
|
}
|
|
|
|
export function getAllMovimientosIndicaciones() {
|
|
const rows = db.prepare('SELECT * FROM movimientos_indicaciones').all();
|
|
return rows;
|
|
}
|