feat(db): migration v2 — due_date columns + pre-migration snapshot
ALTER TABLE notes adds due_date TEXT + due_date_edited_by_user INTEGER. openDb takes <dbFile>.pre-v<N>.bak before running migrations (F6-L1 follow-up #4 — preserves recoverable state if migration fails). NoteRepository: updateAiResult accepts dueDate?, setDueDate + edited-flag CASE WHEN guard mirroring title/summary pattern. Note interface gains dueDate + dueDateEditedByUser fields. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -126,4 +126,53 @@ describe('NoteRepository', () => {
|
||||
expect(row.attempts).toBe(1);
|
||||
expect(row.last_error).toBe('boom');
|
||||
});
|
||||
|
||||
it('hydrate returns dueDate=null + dueDateEditedByUser=false on new note', () => {
|
||||
const { id } = repo.create({ rawText: 'x' });
|
||||
const note = repo.findById(id)!;
|
||||
expect(note.dueDate).toBeNull();
|
||||
expect(note.dueDateEditedByUser).toBe(false);
|
||||
});
|
||||
|
||||
it('updateAiResult writes dueDate when edited flag is 0', () => {
|
||||
const { id } = repo.create({ rawText: 'x' });
|
||||
repo.updateAiResult(id, { title: 'AI 제목', summary: 'a\nb\nc', tags: [], provider: 'p', dueDate: '2026-05-01' });
|
||||
const note = repo.findById(id)!;
|
||||
expect(note.dueDate).toBe('2026-05-01');
|
||||
expect(note.dueDateEditedByUser).toBe(false);
|
||||
});
|
||||
|
||||
it('updateAiResult does NOT overwrite dueDate when edited flag is 1', () => {
|
||||
const { id } = repo.create({ rawText: 'x' });
|
||||
repo.updateAiResult(id, { title: 'AI', summary: 'a\nb\nc', tags: [], provider: 'p', dueDate: '2026-05-01' });
|
||||
repo.setDueDate(id, '2026-05-15');
|
||||
repo.updateAiResult(id, { title: 'AI 2', summary: 'd\ne\nf', tags: [], provider: 'p', dueDate: '2026-05-30' });
|
||||
const note = repo.findById(id)!;
|
||||
expect(note.dueDate).toBe('2026-05-15');
|
||||
expect(note.dueDateEditedByUser).toBe(true);
|
||||
});
|
||||
|
||||
it('setDueDate sets due_date and edited flag', () => {
|
||||
const { id } = repo.create({ rawText: 'x' });
|
||||
repo.setDueDate(id, '2026-06-01');
|
||||
const note = repo.findById(id)!;
|
||||
expect(note.dueDate).toBe('2026-06-01');
|
||||
expect(note.dueDateEditedByUser).toBe(true);
|
||||
});
|
||||
|
||||
it('setDueDate(null) clears due_date but keeps edited flag', () => {
|
||||
const { id } = repo.create({ rawText: 'x' });
|
||||
repo.setDueDate(id, '2026-06-01');
|
||||
repo.setDueDate(id, null);
|
||||
const note = repo.findById(id)!;
|
||||
expect(note.dueDate).toBeNull();
|
||||
expect(note.dueDateEditedByUser).toBe(true);
|
||||
});
|
||||
|
||||
it('updateAiResult without dueDate field treats it as null', () => {
|
||||
const { id } = repo.create({ rawText: 'x' });
|
||||
repo.updateAiResult(id, { title: 'AI', summary: 'a\nb\nc', tags: [], provider: 'p' });
|
||||
const note = repo.findById(id)!;
|
||||
expect(note.dueDate).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user