Files
StarPunk/migrations/005_add_fts5_search.sql
Phil Skentelbery b3c1b16617 feat: Add full-text search with FTS5
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>
2025-11-25 10:03:28 -07:00

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.