From 5693371673a81c9b896d56276084aa29b8cd0872 Mon Sep 17 00:00:00 2001 From: Hendrik Date: Fri, 17 Apr 2026 15:11:23 +0200 Subject: [PATCH] feat(profiles): add profile repository Co-Authored-By: Claude Opus 4.7 (1M context) --- src/lib/server/profiles/repository.ts | 37 ++++++++++++++++++++ tests/integration/profile-repository.test.ts | 34 ++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 src/lib/server/profiles/repository.ts create mode 100644 tests/integration/profile-repository.test.ts diff --git a/src/lib/server/profiles/repository.ts b/src/lib/server/profiles/repository.ts new file mode 100644 index 0000000..164dad2 --- /dev/null +++ b/src/lib/server/profiles/repository.ts @@ -0,0 +1,37 @@ +import type Database from 'better-sqlite3'; +import type { Profile } from '$lib/types'; + +export function listProfiles(db: Database.Database): Profile[] { + return db + .prepare('SELECT id, name, avatar_emoji FROM profile ORDER BY name') + .all() as Profile[]; +} + +export function createProfile( + db: Database.Database, + name: string, + avatarEmoji: string | null = null +): Profile { + const trimmed = name.trim(); + if (!trimmed) throw new Error('Profile name cannot be empty'); + return db + .prepare( + `INSERT INTO profile(name, avatar_emoji) VALUES (?, ?) + RETURNING id, name, avatar_emoji` + ) + .get(trimmed, avatarEmoji) as Profile; +} + +export function renameProfile( + db: Database.Database, + id: number, + newName: string +): void { + const trimmed = newName.trim(); + if (!trimmed) throw new Error('Profile name cannot be empty'); + db.prepare('UPDATE profile SET name = ? WHERE id = ?').run(trimmed, id); +} + +export function deleteProfile(db: Database.Database, id: number): void { + db.prepare('DELETE FROM profile WHERE id = ?').run(id); +} diff --git a/tests/integration/profile-repository.test.ts b/tests/integration/profile-repository.test.ts new file mode 100644 index 0000000..0992838 --- /dev/null +++ b/tests/integration/profile-repository.test.ts @@ -0,0 +1,34 @@ +import { describe, it, expect } from 'vitest'; +import { openInMemoryForTest } from '../../src/lib/server/db'; +import { + createProfile, + listProfiles, + renameProfile, + deleteProfile +} from '../../src/lib/server/profiles/repository'; + +describe('profile repository', () => { + it('creates, lists, renames, deletes', () => { + const db = openInMemoryForTest(); + const p = createProfile(db, 'Hendrik', '👨‍🍳'); + expect(p.id).toBeGreaterThan(0); + expect(listProfiles(db).length).toBe(1); + + renameProfile(db, p.id, 'Hendrik S.'); + expect(listProfiles(db)[0].name).toBe('Hendrik S.'); + + deleteProfile(db, p.id); + expect(listProfiles(db).length).toBe(0); + }); + + it('rejects duplicate names', () => { + const db = openInMemoryForTest(); + createProfile(db, 'Hendrik'); + expect(() => createProfile(db, 'Hendrik')).toThrow(); + }); + + it('rejects empty name', () => { + const db = openInMemoryForTest(); + expect(() => createProfile(db, ' ')).toThrow(/empty/i); + }); +});