From 2218599106dc16d918b8b902f46240ca0a8e4b5b Mon Sep 17 00:00:00 2001 From: Sjoerd de Vries Date: Wed, 20 May 2026 17:42:40 +0200 Subject: [PATCH] feat: session queries --- src/__tests__/db/sessions.test.ts | 49 +++++++++++++++++++++++++++++++ src/db/sessions.ts | 36 +++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 src/__tests__/db/sessions.test.ts create mode 100644 src/db/sessions.ts diff --git a/src/__tests__/db/sessions.test.ts b/src/__tests__/db/sessions.test.ts new file mode 100644 index 0000000..69520ff --- /dev/null +++ b/src/__tests__/db/sessions.test.ts @@ -0,0 +1,49 @@ +import { getDb, resetDb } from '../../db'; +import { insertSession, getSessionByDate, getSessionsInRange, getRecentSessions } from '../../db/sessions'; + +beforeEach(() => { + resetDb(); +}); + +describe('sessions', () => { + it('inserts a session and retrieves it by date', () => { + const db = getDb(); + insertSession(db, '2026-05-20', 60, null); + const s = getSessionByDate(db, '2026-05-20'); + expect(s).not.toBeNull(); + expect(s!.duration_min).toBe(60); + expect(s!.notes).toBeNull(); + }); + + it('inserts a session with notes', () => { + const db = getDb(); + insertSession(db, '2026-05-20', 45, 'felt good'); + const s = getSessionByDate(db, '2026-05-20'); + expect(s!.notes).toBe('felt good'); + }); + + it('returns null for a date with no session', () => { + const db = getDb(); + expect(getSessionByDate(db, '2026-05-20')).toBeNull(); + }); + + it('returns sessions in date range ordered by date asc', () => { + const db = getDb(); + insertSession(db, '2026-05-22', 60, null); + insertSession(db, '2026-05-20', 45, null); + const rows = getSessionsInRange(db, '2026-05-20', '2026-05-22'); + expect(rows).toHaveLength(2); + expect(rows[0]!.date).toBe('2026-05-20'); + }); + + it('returns the N most recent sessions ordered by date desc', () => { + const db = getDb(); + insertSession(db, '2026-05-18', 30, null); + insertSession(db, '2026-05-19', 45, null); + insertSession(db, '2026-05-20', 60, null); + const rows = getRecentSessions(db, 2); + expect(rows).toHaveLength(2); + expect(rows[0]!.date).toBe('2026-05-20'); + expect(rows[1]!.date).toBe('2026-05-19'); + }); +}); diff --git a/src/db/sessions.ts b/src/db/sessions.ts new file mode 100644 index 0000000..e834c93 --- /dev/null +++ b/src/db/sessions.ts @@ -0,0 +1,36 @@ +import type { Database } from 'better-sqlite3'; + +export interface Session { + id: number; + date: string; + duration_min: number; + notes: string | null; + created_at: string; +} + +export function insertSession(db: Database, date: string, duration_min: number, notes: string | null): Session { + const result = db.prepare( + 'INSERT INTO sessions (date, duration_min, notes) VALUES (?, ?, ?)' + ).run(date, duration_min, notes); + return getSessionById(db, result.lastInsertRowid as number)!; +} + +function getSessionById(db: Database, id: number): Session | null { + return (db.prepare('SELECT * FROM sessions WHERE id = ?').get(id) as Session | undefined) ?? null; +} + +export function getSessionByDate(db: Database, date: string): Session | null { + return (db.prepare('SELECT * FROM sessions WHERE date = ?').get(date) as Session | undefined) ?? null; +} + +export function getSessionsInRange(db: Database, from: string, to: string): Session[] { + return db.prepare( + 'SELECT * FROM sessions WHERE date >= ? AND date <= ? ORDER BY date ASC' + ).all(from, to) as Session[]; +} + +export function getRecentSessions(db: Database, limit: number): Session[] { + return db.prepare( + 'SELECT * FROM sessions ORDER BY date DESC LIMIT ?' + ).all(limit) as Session[]; +}