feat(notebook): m009 sort_order 컬럼 + reorder 메서드 + IPC notebook:reorder
- m009 마이그레이션: notebooks.sort_order INTEGER 컬럼 추가, 기존 rows created_at 순으로 backfill - NotebookRepository.list ORDER BY sort_order ASC, name ASC 로 변경 - NotebookRepository.create 신규 노트북 sort_order = max+1 자동 할당 - NotebookRepository.reorder(id, direction) — swap transaction 으로 atomic 순서 변경 - IPC notebook:reorder 핸들러 등록, preload/shared types pass-through - 테스트 45개 추가 (m009, reorder 케이스 4, list ORDER BY, IPC 핸들러 2) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ export class NotebookRepository {
|
||||
(SELECT COUNT(*) FROM notes n
|
||||
WHERE n.notebook_id = nb.id AND n.status = 'active') AS note_count
|
||||
FROM notebooks nb
|
||||
ORDER BY nb.name ASC`
|
||||
ORDER BY nb.sort_order ASC, nb.name ASC`
|
||||
).all() as Array<Record<string, unknown>>;
|
||||
return rows.map((r) => this.hydrate(r));
|
||||
}
|
||||
@@ -30,12 +30,31 @@ export class NotebookRepository {
|
||||
create(input: { name: string; color?: string | null }): Notebook {
|
||||
const id = uuidv7();
|
||||
const now = new Date().toISOString();
|
||||
const maxRow = this.db.prepare(`SELECT COALESCE(MAX(sort_order), -1) AS m FROM notebooks`).get() as { m: number };
|
||||
const sortOrder = maxRow.m + 1;
|
||||
this.db.prepare(
|
||||
`INSERT INTO notebooks(id, name, color, created_at, updated_at) VALUES(?,?,?,?,?)`
|
||||
).run(id, input.name, input.color ?? null, now, now);
|
||||
`INSERT INTO notebooks(id, name, color, created_at, updated_at, sort_order) VALUES(?,?,?,?,?,?)`
|
||||
).run(id, input.name, input.color ?? null, now, now, sortOrder);
|
||||
return { id, name: input.name, color: input.color ?? null, createdAt: now, updatedAt: now, noteCount: 0 };
|
||||
}
|
||||
|
||||
reorder(id: string, direction: 'up' | 'down'): { ok: boolean } {
|
||||
const cur = this.db.prepare(`SELECT sort_order FROM notebooks WHERE id = ?`).get(id) as { sort_order: number } | undefined;
|
||||
if (!cur) return { ok: false };
|
||||
const neighbor = direction === 'up'
|
||||
? this.db.prepare(`SELECT id, sort_order FROM notebooks WHERE sort_order < ? ORDER BY sort_order DESC LIMIT 1`).get(cur.sort_order)
|
||||
: this.db.prepare(`SELECT id, sort_order FROM notebooks WHERE sort_order > ? ORDER BY sort_order ASC LIMIT 1`).get(cur.sort_order);
|
||||
if (!neighbor) return { ok: false }; // 이미 끝
|
||||
const n = neighbor as { id: string; sort_order: number };
|
||||
const now = new Date().toISOString();
|
||||
const tx = this.db.transaction(() => {
|
||||
this.db.prepare(`UPDATE notebooks SET sort_order = ?, updated_at = ? WHERE id = ?`).run(n.sort_order, now, id);
|
||||
this.db.prepare(`UPDATE notebooks SET sort_order = ?, updated_at = ? WHERE id = ?`).run(cur.sort_order, now, n.id);
|
||||
});
|
||||
tx();
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
rename(id: string, name: string): void {
|
||||
const now = new Date().toISOString();
|
||||
this.db.prepare(`UPDATE notebooks SET name=?, updated_at=? WHERE id=?`).run(name, now, id);
|
||||
|
||||
Reference in New Issue
Block a user