87 lines
3.1 KiB
TypeScript
87 lines
3.1 KiB
TypeScript
import Database from 'better-sqlite3';
|
|
import { mkdirSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import type { SleepEntry } from './sleep';
|
|
|
|
const dataDirectory = process.env.DATA_DIR ?? join(process.cwd(), 'data');
|
|
mkdirSync(dataDirectory, { recursive: true });
|
|
|
|
const database = new Database(join(dataDirectory, 'sleepy.db'));
|
|
database.pragma('journal_mode = WAL');
|
|
database.exec(`
|
|
CREATE TABLE IF NOT EXISTS sleep_entries (
|
|
date TEXT PRIMARY KEY NOT NULL,
|
|
napped INTEGER NOT NULL DEFAULT 0,
|
|
nap_start TEXT,
|
|
nap_duration_minutes INTEGER,
|
|
bedtime TEXT NOT NULL,
|
|
sleep_latency_minutes INTEGER NOT NULL,
|
|
awakenings INTEGER NOT NULL,
|
|
waso_minutes INTEGER NOT NULL,
|
|
rise_time TEXT NOT NULL,
|
|
alarm_type TEXT NOT NULL,
|
|
rating INTEGER NOT NULL,
|
|
notes TEXT NOT NULL DEFAULT '',
|
|
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
`);
|
|
|
|
type SleepEntryRow = Omit<SleepEntry, 'napped' | 'napStart' | 'napDurationMinutes' | 'sleepLatencyMinutes' | 'wasoMinutes' | 'riseTime' | 'alarmType' | 'createdAt' | 'updatedAt'> & {
|
|
napped: number;
|
|
nap_start: string | null;
|
|
nap_duration_minutes: number | null;
|
|
sleep_latency_minutes: number;
|
|
waso_minutes: number;
|
|
rise_time: string;
|
|
alarm_type: SleepEntry['alarmType'];
|
|
created_at: string;
|
|
updated_at: string;
|
|
};
|
|
|
|
function mapEntry(row: SleepEntryRow): SleepEntry {
|
|
return {
|
|
date: row.date,
|
|
napped: Boolean(row.napped),
|
|
napStart: row.nap_start,
|
|
napDurationMinutes: row.nap_duration_minutes,
|
|
bedtime: row.bedtime,
|
|
sleepLatencyMinutes: row.sleep_latency_minutes,
|
|
awakenings: row.awakenings,
|
|
wasoMinutes: row.waso_minutes,
|
|
riseTime: row.rise_time,
|
|
alarmType: row.alarm_type,
|
|
rating: row.rating,
|
|
notes: row.notes,
|
|
createdAt: row.created_at,
|
|
updatedAt: row.updated_at,
|
|
};
|
|
}
|
|
|
|
export function getEntry(date: string): SleepEntry | null {
|
|
const row = database.prepare('SELECT * FROM sleep_entries WHERE date = ?').get(date) as SleepEntryRow | undefined;
|
|
return row ? mapEntry(row) : null;
|
|
}
|
|
|
|
export function saveEntry(entry: SleepEntry): SleepEntry {
|
|
database.prepare(`
|
|
INSERT INTO sleep_entries (
|
|
date, napped, nap_start, nap_duration_minutes, bedtime, sleep_latency_minutes,
|
|
awakenings, waso_minutes, rise_time, alarm_type, rating, notes
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT(date) DO UPDATE SET
|
|
napped = excluded.napped, nap_start = excluded.nap_start,
|
|
nap_duration_minutes = excluded.nap_duration_minutes, bedtime = excluded.bedtime,
|
|
sleep_latency_minutes = excluded.sleep_latency_minutes, awakenings = excluded.awakenings,
|
|
waso_minutes = excluded.waso_minutes, rise_time = excluded.rise_time,
|
|
alarm_type = excluded.alarm_type, rating = excluded.rating, notes = excluded.notes,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
`).run(
|
|
entry.date, Number(entry.napped), entry.napStart, entry.napDurationMinutes, entry.bedtime,
|
|
entry.sleepLatencyMinutes, entry.awakenings, entry.wasoMinutes, entry.riseTime,
|
|
entry.alarmType, entry.rating, entry.notes,
|
|
);
|
|
|
|
return getEntry(entry.date) ?? entry;
|
|
}
|