diff --git a/src/main/repository/NoteRepository.ts b/src/main/repository/NoteRepository.ts index d863777..c67029f 100644 --- a/src/main/repository/NoteRepository.ts +++ b/src/main/repository/NoteRepository.ts @@ -231,6 +231,13 @@ export class NoteRepository { tx(); } + restore(id: string): void { + const now = new Date().toISOString(); + this.db + .prepare(`UPDATE notes SET deleted_at = NULL, updated_at = ? WHERE id = ?`) + .run(now, id); + } + delete(id: string): void { this.db.prepare('DELETE FROM notes WHERE id=?').run(id); } diff --git a/tests/unit/NoteRepository.test.ts b/tests/unit/NoteRepository.test.ts index 2aa2579..3c7042a 100644 --- a/tests/unit/NoteRepository.test.ts +++ b/tests/unit/NoteRepository.test.ts @@ -246,3 +246,37 @@ describe('NoteRepository.trash', () => { expect(() => repo.trash('nonexistent', '2026-05-01T12:00:00.000Z')).not.toThrow(); }); }); + +describe('NoteRepository.restore', () => { + let db: Database.Database; + let repo: NoteRepository; + + beforeEach(() => { + db = new Database(':memory:'); + runMigrations(db); + repo = new NoteRepository(db); + }); + + it('clears deleted_at on a trashed note', () => { + const { id } = repo.create({ rawText: 'x' }); + repo.trash(id, '2026-05-01T12:00:00.000Z'); + repo.restore(id); + const note = repo.findById(id)!; + expect(note.deletedAt).toBeNull(); + }); + + it('updates updated_at', () => { + const { id } = repo.create({ rawText: 'x' }); + repo.trash(id, '2026-05-01T12:00:00.000Z'); + const before = repo.findById(id)!.updatedAt; + repo.restore(id); + const after = repo.findById(id)!.updatedAt; + expect(after).not.toBe(before); + }); + + it('is no-op on already-active note', () => { + const { id } = repo.create({ rawText: 'x' }); + expect(() => repo.restore(id)).not.toThrow(); + expect(repo.findById(id)!.deletedAt).toBeNull(); + }); +});