feat: deliver P2 v0.2.0 with unified editor, search, and snapshots
Implement schema v2 migration, outline/setting/inspiration CRUD, unified TipTap editing, reference panel with mentions, FTS global search, chapter version history, writing landmarks, word frequency analysis, light theme contrast fixes, and full unit/E2E test coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import type { SearchSourceKind } from '../../shared/types'
|
||||
import { stripHtml } from './word-count'
|
||||
import type { SqliteDb } from '../db/types'
|
||||
|
||||
export class FtsSyncService {
|
||||
upsert(db: SqliteDb, kind: SearchSourceKind, id: string, title: string, body: string): void {
|
||||
const plainBody = stripHtml(body)
|
||||
db.prepare('DELETE FROM search_fts WHERE source_kind = ? AND source_id = ?').run(kind, id)
|
||||
db.prepare(
|
||||
'INSERT INTO search_fts (source_kind, source_id, title, body) VALUES (?, ?, ?, ?)'
|
||||
).run(kind, id, title, plainBody)
|
||||
}
|
||||
|
||||
remove(db: SqliteDb, kind: SearchSourceKind, id: string): void {
|
||||
db.prepare('DELETE FROM search_fts WHERE source_kind = ? AND source_id = ?').run(kind, id)
|
||||
}
|
||||
|
||||
rebuildAll(db: SqliteDb): void {
|
||||
db.exec('DELETE FROM search_fts')
|
||||
|
||||
const chapters = db.prepare('SELECT id, title, content FROM chapters').all() as {
|
||||
id: string
|
||||
title: string
|
||||
content: string
|
||||
}[]
|
||||
for (const ch of chapters) {
|
||||
this.upsert(db, 'chapter', ch.id, ch.title, ch.content)
|
||||
}
|
||||
|
||||
const outlines = db.prepare('SELECT id, title, description FROM outline_items').all() as {
|
||||
id: string
|
||||
title: string
|
||||
description: string
|
||||
}[]
|
||||
for (const o of outlines) {
|
||||
this.upsert(db, 'outline', o.id, o.title, o.description)
|
||||
}
|
||||
|
||||
const settings = db.prepare('SELECT id, name, description FROM settings').all() as {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
}[]
|
||||
for (const s of settings) {
|
||||
this.upsert(db, 'setting', s.id, s.name, s.description)
|
||||
}
|
||||
|
||||
const inspirations = db.prepare('SELECT id, title, content FROM inspiration').all() as {
|
||||
id: string
|
||||
title: string
|
||||
content: string
|
||||
}[]
|
||||
for (const i of inspirations) {
|
||||
this.upsert(db, 'inspiration', i.id, i.title, i.content)
|
||||
}
|
||||
|
||||
const bookmarks = db.prepare('SELECT id, label, chapter_id FROM bookmarks').all() as {
|
||||
id: string
|
||||
label: string
|
||||
chapter_id: string
|
||||
}[]
|
||||
for (const b of bookmarks) {
|
||||
this.upsert(db, 'bookmark', b.id, b.label, b.label)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const ftsSync = new FtsSyncService()
|
||||
Reference in New Issue
Block a user