feat(notes): notebook_id 필드 + create/upsert 시 default notebook 보장
Note.notebookId 필드 추가(required), NoteRepository.create/importNote/upsertFromSync INSERT 에 notebook_id 컬럼 포함 — 미지정 시 getDefaultNotebookId() 로 가장 오래된 notebook 자동 할당. hydrate 에 notebookId 반환 추가. 관련 test fixture 5곳 notebookId 보강. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -69,7 +69,8 @@ const baseNote: Note = {
|
||||
media: [
|
||||
{ id: 'm1', kind: 'image', relPath: 'media/n1/img1.png', mime: 'image/png', bytes: 100 },
|
||||
{ id: 'm2', kind: 'image', relPath: 'media/n1/img2.jpg', mime: 'image/jpeg', bytes: 200 }
|
||||
]
|
||||
],
|
||||
notebookId: 'nb-default'
|
||||
};
|
||||
|
||||
describe('NoteCard — image rendering', () => {
|
||||
|
||||
@@ -1222,3 +1222,36 @@ describe('NoteRepository — notes_fts tags sync (v0.2.11 Cut D)', () => {
|
||||
expect(row.tags).toBe('결재');
|
||||
});
|
||||
});
|
||||
|
||||
describe('NoteRepository.create with notebook', () => {
|
||||
let db: Database.Database;
|
||||
let repo: NoteRepository;
|
||||
let defaultId: string;
|
||||
|
||||
beforeEach(() => {
|
||||
db = new Database(':memory:');
|
||||
db.pragma('foreign_keys = ON');
|
||||
runMigrations(db);
|
||||
repo = new NoteRepository(db);
|
||||
defaultId = (db.prepare(`SELECT id FROM notebooks`).get() as { id: string }).id;
|
||||
});
|
||||
|
||||
it('notebook_id 미지정 시 default notebook 으로 들어감', () => {
|
||||
const { id } = repo.create({ rawText: 'hello' });
|
||||
const r = repo.findById(id);
|
||||
expect(r?.notebookId).toBe(defaultId);
|
||||
});
|
||||
|
||||
it('notebook_id 지정 시 그 값 보존', () => {
|
||||
db.prepare(`INSERT INTO notebooks(id,name,created_at,updated_at) VALUES('nb-other','회사','2026-05-14','2026-05-14')`).run();
|
||||
const { id } = repo.create({ rawText: 'hi', notebookId: 'nb-other' });
|
||||
expect(repo.findById(id)?.notebookId).toBe('nb-other');
|
||||
});
|
||||
|
||||
it('hydrate 가 notebookId 필드 반환', () => {
|
||||
const { id } = repo.create({ rawText: 'hi' });
|
||||
const r = repo.findById(id);
|
||||
expect(typeof r?.notebookId).toBe('string');
|
||||
expect(r?.notebookId).toBe(defaultId);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ const noteStub = (id: string): Note => ({
|
||||
deletedAt: null, lastRecalledAt: null, recallDismissedAt: null,
|
||||
status: 'active', statusChangedAt: null, moveReason: null,
|
||||
createdAt: '2026-05-01T00:00:00Z', updatedAt: '2026-05-01T00:00:00Z',
|
||||
tags: [], media: []
|
||||
tags: [], media: [], notebookId: 'nb-default'
|
||||
});
|
||||
|
||||
describe('useInbox — expired state (v0.2.3 #5)', () => {
|
||||
|
||||
@@ -38,7 +38,8 @@ const note = (id: string): Note => ({
|
||||
userIntent: null, intentPromptedAt: null,
|
||||
createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
|
||||
deletedAt: null, lastRecalledAt: null, recallDismissedAt: null,
|
||||
status: 'active', statusChangedAt: null, moveReason: null
|
||||
status: 'active', statusChangedAt: null, moveReason: null,
|
||||
notebookId: 'nb-default'
|
||||
});
|
||||
|
||||
describe('store recall actions', () => {
|
||||
|
||||
@@ -27,7 +27,8 @@ function sample(id: string, tags: string[]): Note {
|
||||
createdAt: '2026-04-26T00:00:00Z',
|
||||
updatedAt: '2026-04-26T00:00:00Z',
|
||||
tags: tags.map((name) => ({ name, source: 'ai' as const })),
|
||||
media: []
|
||||
media: [],
|
||||
notebookId: 'nb-default'
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ const noteStub = (id: string, deletedAt: string | null = null): Note => ({
|
||||
deletedAt, lastRecalledAt: null, recallDismissedAt: null,
|
||||
status: deletedAt ? 'trashed' : 'active', statusChangedAt: deletedAt, moveReason: null,
|
||||
createdAt: '2026-05-01T00:00:00Z', updatedAt: '2026-05-01T00:00:00Z',
|
||||
tags: [], media: []
|
||||
tags: [], media: [], notebookId: 'nb-default'
|
||||
});
|
||||
|
||||
describe('useInbox — trash state (v0.2.3 #4)', () => {
|
||||
|
||||
Reference in New Issue
Block a user