longevity: misureValideAlla, spareggio sulla riga e nota sulla conferma dei fuori range
Refs #1 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -144,15 +144,21 @@ export const FINESTRA_GIORNI: number | null = null;
|
||||
* questionario del giorno D, e viceversa una sessione del giorno D-1 non vede nulla di ciò
|
||||
* che accadrà dopo di lei.
|
||||
*
|
||||
* "Più recente" = data della sessione DESC, poi id DESC (a parità di data, l'inserimento
|
||||
* più tardo vince) — stesso criterio di `leggiScore`. A parità di sessione (una misura
|
||||
* ri-registrata più volte nella stessa sessione, oggi non capita ma non è vietato) vince
|
||||
* comunque la più recente per `id` di riga in `misure`, perché la query è ordinata anche
|
||||
* su quello implicitamente tramite l'ordine della sessione.
|
||||
* "Più recente" = data della sessione DESC, poi id di sessione DESC (a parità di data,
|
||||
* l'inserimento più tardo vince) — stesso criterio di `leggiScore`. A parità di SESSIONE
|
||||
* (due misure dello stesso test_id nella stessa sessione: `registraMisure` non lo vieta,
|
||||
* es. una correzione manuale dopo un refuso) l'ORDER BY aggiunge un terzo criterio
|
||||
* esplicito, `m.id` di riga in `misure` DESC: vince quella scritta dopo. Senza questo
|
||||
* terzo criterio le due righe uscirebbero in un ordine NON definito da SQL (nessuna delle
|
||||
* due chiavi precedenti le distingue), non "implicito" come diceva una versione precedente
|
||||
* di questo commento — un ordine che sembra stabile per come SQLite le restituisce oggi,
|
||||
* ma su cui non si può contare.
|
||||
*
|
||||
* Stessa esclusione di `fuori_range = 1` che c'era prima nella lettura diretta (§9 della
|
||||
* spec): una misura fuori dal range dichiarato non entra, né dalla sessione corrente né da
|
||||
* una precedente.
|
||||
* una precedente. La colonna della conferma non esiste ancora (§12 della spec, issue #7):
|
||||
* quando ci sarà, questo filtro andrà rilassato per lasciar passare le misure confermate,
|
||||
* non tolto del tutto.
|
||||
*/
|
||||
export function misureValideAlla(db: Database.Database, sessioneId: number): Map<string, number> {
|
||||
const sessione = db.prepare(
|
||||
@@ -166,13 +172,16 @@ export function misureValideAlla(db: Database.Database, sessioneId: number): Map
|
||||
JOIN sessioni s2 ON s2.id = m.sessione_id
|
||||
WHERE m.client_code = ? AND m.fuori_range = 0 AND m.valore_num IS NOT NULL
|
||||
AND (s2.data < ? OR (s2.data = ? AND s2.id <= ?))
|
||||
ORDER BY s2.data DESC, s2.id DESC`
|
||||
ORDER BY s2.data DESC, s2.id DESC, m.id DESC`
|
||||
).all(sessione.client_code, sessione.data, sessione.data, sessione.id) as
|
||||
{ test_id: string; valore_num: number; data: string }[];
|
||||
|
||||
const mappa = new Map<string, number>();
|
||||
for (const r of righe) {
|
||||
if (mappa.has(r.test_id)) continue; // gia' trovato un valore piu' recente per questo test_id
|
||||
// gia' trovato un valore per questo test_id: e' il piu' recente, per data di sessione,
|
||||
// poi id di sessione, poi (spareggio) id di riga in misure — tutti e tre espliciti
|
||||
// nell'ORDER BY qui sopra, la prima riga per test_id in questo ciclo e' sempre quella giusta.
|
||||
if (mappa.has(r.test_id)) continue;
|
||||
if (FINESTRA_GIORNI !== null) {
|
||||
const giorni = (Date.parse(sessione.data) - Date.parse(r.data)) / 86_400_000;
|
||||
if (giorni > FINESTRA_GIORNI) continue;
|
||||
|
||||
@@ -198,6 +198,20 @@ describe('un check-up e un questionario sono sessioni separate, ma un cliente e
|
||||
expect(sd).not.toHaveProperty('questionario_lifestyle');
|
||||
});
|
||||
|
||||
it('due misure dello stesso test_id nella stessa sessione: vince quella inserita dopo', () => {
|
||||
// registraMisure non vieta di scrivere due volte lo stesso test_id nella stessa
|
||||
// sessione (es. una correzione manuale dopo un refuso di battitura). data di sessione
|
||||
// e id di sessione sono identici per le due righe: senza uno spareggio esplicito su
|
||||
// m.id (la riga in `misure`), l'ordine fra le due sarebbe indefinito.
|
||||
const db = dbPronto('ISL-0023', 'M');
|
||||
const s = apriSessione(db, { client_code: 'ISL-0023', data: '2026-08-05', tipo: 'checkup', eta_alla_data: 38 });
|
||||
registraMisure(db, s, 'manuale', [{ test_id: 'f_grasso_pct', valore_num: 20 }]); // scritta per prima, refuso
|
||||
registraMisure(db, s, 'manuale', [{ test_id: 'f_grasso_pct', valore_num: 12.8 }]); // corretta subito dopo
|
||||
|
||||
const misurate = misureValideAlla(db, s);
|
||||
expect(misurate.get('f_grasso_pct')).toBe(12.8); // l'ultima scritta, non la prima
|
||||
});
|
||||
|
||||
it('una misura fuori range viene ignorata e sostituita dalla precedente misura valida', () => {
|
||||
const db = dbPronto('ISL-0022', 'M');
|
||||
const s1 = apriSessione(db, { client_code: 'ISL-0022', data: '2026-08-05', tipo: 'checkup', eta_alla_data: 38 });
|
||||
|
||||
Reference in New Issue
Block a user