9943312071
Implementa il modulo che unisce i due database (identity e longevity) rispettando la separazione richiesta dal cliente: pseudonimizzazione dei dati clinici. Il modulo esporta tre funzioni: - creaCliente: registra un soggetto con il suo codice progressivo ISL-NNNN - codicePerUtente: risale dal user_id del sito al client_code - etaAllaData: calcola l'eta' al momento della misura (non la data di nascita) Un test verifica che nessun altro modulo apra entrambe le connessioni, preservando il firewall fra dati clinici e identita'. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
60 lines
2.7 KiB
TypeScript
60 lines
2.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { readFileSync, readdirSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { createLongevityDb, createIdentityDb } from '../../src/lib/longevity/db';
|
|
import { creaCliente, codicePerUtente, etaAllaData } from '../../src/lib/longevity/anagrafica';
|
|
|
|
describe('anagrafica pseudonimizzata', () => {
|
|
it('il nome sta in identity, il sesso in longevity, e i due non si mescolano', () => {
|
|
const id = createIdentityDb(':memory:');
|
|
const lg = createLongevityDb(':memory:');
|
|
const code = creaCliente(id, lg, { nome: 'Mario', cognome: 'Rossi', sesso: 'M', data_nascita: '1988-03-04' });
|
|
|
|
const inIdentity = id.prepare(`SELECT nome, cognome FROM clienti WHERE client_code = ?`).get(code) as
|
|
{ nome: string; cognome: string };
|
|
expect(inIdentity.nome).toBe('Mario');
|
|
|
|
const inLongevity = lg.prepare(`SELECT sesso FROM soggetti WHERE client_code = ?`).get(code) as { sesso: string };
|
|
expect(inLongevity.sesso).toBe('M');
|
|
|
|
// in longevity non deve esistere nessuna colonna che contenga il nome
|
|
const dump = JSON.stringify(lg.prepare(`SELECT * FROM soggetti`).all());
|
|
expect(dump).not.toContain('Mario');
|
|
expect(dump).not.toContain('Rossi');
|
|
expect(dump).not.toContain('1988-03-04');
|
|
});
|
|
|
|
it('assegna codici progressivi e non riusa i vecchi', () => {
|
|
const id = createIdentityDb(':memory:');
|
|
const lg = createLongevityDb(':memory:');
|
|
const a = creaCliente(id, lg, { nome: 'A', cognome: 'A', sesso: 'F' });
|
|
const b = creaCliente(id, lg, { nome: 'B', cognome: 'B', sesso: 'M' });
|
|
expect(a).toMatch(/^ISL-\d{4}$/);
|
|
expect(b).not.toBe(a);
|
|
});
|
|
|
|
it('ritrova il codice a partire dall utente del sito', () => {
|
|
const id = createIdentityDb(':memory:');
|
|
const lg = createLongevityDb(':memory:');
|
|
const code = creaCliente(id, lg, { nome: 'C', cognome: 'C', sesso: 'F', user_id: 42 });
|
|
expect(codicePerUtente(id, 42)).toBe(code);
|
|
expect(codicePerUtente(id, 99)).toBeNull();
|
|
});
|
|
|
|
it('calcola l eta alla data della sessione', () => {
|
|
expect(etaAllaData('1988-03-04', '2026-08-21')).toBe(38);
|
|
expect(etaAllaData('1988-12-31', '2026-08-21')).toBe(37); // compleanno non ancora passato
|
|
});
|
|
|
|
it('nessun altro modulo apre entrambe le connessioni', () => {
|
|
const dir = join(process.cwd(), 'src/lib/longevity');
|
|
const colpevoli: string[] = [];
|
|
for (const f of readdirSync(dir)) {
|
|
if (!f.endsWith('.ts') || f === 'anagrafica.ts' || f === 'db.ts') continue;
|
|
const src = readFileSync(join(dir, f), 'utf8');
|
|
if (src.includes('createIdentityDb') && src.includes('createLongevityDb')) colpevoli.push(f);
|
|
}
|
|
expect(colpevoli).toEqual([]);
|
|
});
|
|
});
|