Implements FTS5-based full-text search for notes as specified in ADR-034. Changes: - Created migration 005_add_fts5_search.sql with FTS5 virtual table - Created starpunk/search.py module with search functions - Integrated FTS index updates into create_note() and update_note() - DELETE trigger automatically removes notes from FTS index - INSERT/UPDATE handled by application code (files not in DB) Features: - Porter stemming for better English search - Unicode normalization for international characters - Relevance ranking with snippets - Graceful degradation if FTS5 unavailable - Helper function to rebuild index if needed Note: Initial FTS index population needs to be added to app startup. Part of v1.1.0 (Phase 3). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
45 lines
1.9 KiB
SQL
45 lines
1.9 KiB
SQL
-- Migration 005: Add full-text search using FTS5
|
|
--
|
|
-- Creates FTS5 virtual table for full-text search of notes.
|
|
-- Since note content is stored in external files (not in the database),
|
|
-- the FTS index must be maintained by application code, not SQL triggers.
|
|
--
|
|
-- Requirements:
|
|
-- - SQLite compiled with FTS5 support
|
|
-- - Application code handles index synchronization
|
|
--
|
|
-- Features:
|
|
-- - Full-text search on note content
|
|
-- - Porter stemming for better English search results
|
|
-- - Unicode normalization for international characters
|
|
-- - rowid matches notes.id for efficient lookups
|
|
|
|
-- Create FTS5 virtual table for note search
|
|
-- Using porter stemmer for better English search results
|
|
-- Unicode61 tokenizer for international character support
|
|
-- Note: slug is UNINDEXED (not searchable, just for result display)
|
|
CREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(
|
|
slug UNINDEXED, -- Slug for result linking (not searchable)
|
|
title, -- First line of note (searchable, high weight)
|
|
content, -- Full markdown content (searchable)
|
|
tokenize='porter unicode61'
|
|
);
|
|
|
|
-- Create delete trigger to remove from FTS when note is deleted
|
|
-- This is the only trigger we can use since deletion doesn't require file access
|
|
CREATE TRIGGER IF NOT EXISTS notes_fts_delete
|
|
AFTER DELETE ON notes
|
|
BEGIN
|
|
DELETE FROM notes_fts WHERE rowid = OLD.id;
|
|
END;
|
|
|
|
-- Note: INSERT and UPDATE triggers cannot be used because they would need
|
|
-- to read content from external files, which SQLite triggers cannot do.
|
|
-- The application code in starpunk/notes.py handles FTS updates for
|
|
-- create and update operations.
|
|
|
|
-- Initial index population:
|
|
-- After this migration runs, the FTS index must be populated with existing notes.
|
|
-- This happens automatically on application startup via starpunk/search.py:rebuild_fts_index()
|
|
-- or can be triggered manually if needed.
|