feat(01-02): create EntryRepository with typed CRUD operations

- Implement EntryRepository interface with create, getById, getAll, update, delete, count
- SQLiteEntryRepository class using Drizzle ORM
- Automatic ID generation with nanoid
- Automatic timestamp management (createdAt, updatedAt)
- Pagination support via limit/offset
- Singleton pattern for consistent access
This commit is contained in:
Thomas Richter
2026-01-29 04:37:37 +01:00
parent 4c2e8fe366
commit a15dbfd3d8

View File

@@ -0,0 +1,68 @@
import { eq, desc } from 'drizzle-orm';
import { db } from './index';
import { entries, type Entry, type NewEntry } from './schema';
import { nanoid } from 'nanoid';
export interface EntryRepository {
create(entry: Omit<NewEntry, 'id' | 'createdAt' | 'updatedAt'>): Entry;
getById(id: string): Entry | undefined;
getAll(options?: { limit?: number; offset?: number }): Entry[];
update(id: string, updates: Partial<Omit<Entry, 'id' | 'createdAt'>>): Entry | undefined;
delete(id: string): boolean;
count(): number;
}
class SQLiteEntryRepository implements EntryRepository {
create(entry: Omit<NewEntry, 'id' | 'createdAt' | 'updatedAt'>): Entry {
const now = new Date().toISOString();
const newEntry: NewEntry = {
...entry,
id: nanoid(),
createdAt: now,
updatedAt: now
};
db.insert(entries).values(newEntry).run();
return this.getById(newEntry.id)!;
}
getById(id: string): Entry | undefined {
return db.select().from(entries).where(eq(entries.id, id)).get();
}
getAll(options: { limit?: number; offset?: number } = {}): Entry[] {
const { limit = 100, offset = 0 } = options;
return db.select().from(entries).orderBy(desc(entries.createdAt)).limit(limit).offset(offset).all();
}
update(id: string, updates: Partial<Omit<Entry, 'id' | 'createdAt'>>): Entry | undefined {
const existing = this.getById(id);
if (!existing) return undefined;
db.update(entries)
.set({
...updates,
updatedAt: new Date().toISOString()
})
.where(eq(entries.id, id))
.run();
return this.getById(id);
}
delete(id: string): boolean {
const existing = this.getById(id);
if (!existing) return false;
db.delete(entries).where(eq(entries.id, id)).run();
return true;
}
count(): number {
const result = db.select().from(entries).all();
return result.length;
}
}
// Singleton instance
export const entryRepository: EntryRepository = new SQLiteEntryRepository();