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:
altair823
2026-04-26 11:05:44 +09:00
parent cfd34c352b
commit 0bb6c12bbb
8 changed files with 129 additions and 8 deletions

View File

@@ -100,15 +100,17 @@ export class NoteRepository {
updateAiResult(
id: string,
result: { title: string; summary: string; tags: string[]; provider: string }
result: { title: string; summary: string; tags: string[]; provider: string; dueDate?: string | null }
): void {
const now = new Date().toISOString();
const dueDate = result.dueDate ?? null;
const tx = this.db.transaction(() => {
this.db
.prepare(
`UPDATE notes
SET ai_title = CASE WHEN title_edited_by_user = 1 THEN ai_title ELSE ? END,
ai_summary = CASE WHEN summary_edited_by_user = 1 THEN ai_summary ELSE ? END,
due_date = CASE WHEN due_date_edited_by_user = 1 THEN due_date ELSE ? END,
ai_status = 'done',
ai_provider = ?,
ai_generated_at = ?,
@@ -116,7 +118,7 @@ export class NoteRepository {
updated_at = ?
WHERE id = ?`
)
.run(result.title, result.summary, result.provider, now, now, id);
.run(result.title, result.summary, dueDate, result.provider, now, now, id);
this.db.prepare(`DELETE FROM note_tags WHERE note_id=? AND source='ai'`).run(id);
const getOrInsertTag = this.db.prepare(
`INSERT INTO tags(name) VALUES(?) ON CONFLICT(name) DO UPDATE SET name=name RETURNING id`
@@ -210,6 +212,15 @@ export class NoteRepository {
.run(now, now, id);
}
setDueDate(id: string, date: string | null): void {
const now = new Date().toISOString();
this.db
.prepare(
`UPDATE notes SET due_date = ?, due_date_edited_by_user = 1, updated_at = ? WHERE id = ?`
)
.run(date, now, id);
}
delete(id: string): void {
this.db.prepare('DELETE FROM notes WHERE id=?').run(id);
}
@@ -340,6 +351,8 @@ export class NoteRepository {
summaryEditedByUser: row.summary_edited_by_user === 1,
userIntent: row.user_intent,
intentPromptedAt: row.intent_prompted_at,
dueDate: row.due_date ?? null,
dueDateEditedByUser: row.due_date_edited_by_user === 1,
createdAt: row.created_at,
updatedAt: row.updated_at,
tags: tags as NoteTag[],