diff --git a/src/lib/Data.php b/src/lib/Data.php index 0d5328f..4bc8ac8 100644 --- a/src/lib/Data.php +++ b/src/lib/Data.php @@ -14,6 +14,31 @@ class Data { return $db; } + /** + * Create the search index and synchronization triggers for the item table + * + * @param SQLite3 $db The database connection on which these will be created + */ + public static function createSearchIndex(SQLite3 $db): void { + $db->exec("CREATE VIRTUAL TABLE item_search USING fts5(content, content='item', content_rowid='id')"); + $db->exec(<<<'SQL' + CREATE TRIGGER item_ai AFTER INSERT ON item BEGIN + INSERT INTO item_search (rowid, content) VALUES (new.id, new.content); + END; + SQL); + $db->exec(<<<'SQL' + CREATE TRIGGER item_au AFTER UPDATE ON item BEGIN + INSERT INTO item_search (item_search, rowid, content) VALUES ('delete', old.id, old.content); + INSERT INTO item_search (rowid, content) VALUES (new.id, new.content); + END; + SQL); + $db->exec(<<<'SQL' + CREATE TRIGGER item_ad AFTER DELETE ON item BEGIN + INSERT INTO item_search (item_search, rowid, content) VALUES ('delete', old.id, old.content); + END; + SQL); + } + /** * Make sure the expected tables exist */ @@ -23,17 +48,16 @@ class Data { $tableQuery = $db->query("SELECT name FROM sqlite_master WHERE type = 'table'"); while ($table = $tableQuery->fetchArray(SQLITE3_NUM)) $tables[] = $table[0]; if (!in_array('frc_user', $tables)) { - $query = <<<'SQL' + $db->exec(<<<'SQL' CREATE TABLE frc_user ( id INTEGER NOT NULL PRIMARY KEY, email TEXT NOT NULL, password TEXT NOT NULL) - SQL; - $db->exec($query); + SQL); $db->exec('CREATE INDEX idx_user_email ON frc_user (email)'); } if (!in_array('feed', $tables)) { - $query = <<<'SQL' + $db->exec(<<<'SQL' CREATE TABLE feed ( id INTEGER NOT NULL PRIMARY KEY, user_id INTEGER NOT NULL, @@ -42,11 +66,10 @@ class Data { updated_on TEXT, checked_on TEXT, FOREIGN KEY (user_id) REFERENCES frc_user (id)) - SQL; - $db->exec($query); + SQL); } if (!in_array('item', $tables)) { - $query = <<<'SQL' + $db->exec(<<<'SQL' CREATE TABLE item ( id INTEGER NOT NULL PRIMARY KEY, feed_id INTEGER NOT NULL, @@ -59,8 +82,8 @@ class Data { is_read BOOLEAN NOT NULL DEFAULT 0, is_bookmarked BOOLEAN NOT NULL DEFAULT 0, FOREIGN KEY (feed_id) REFERENCES feed (id)) - SQL; - $db->exec($query); + SQL); + self::createSearchIndex($db); } $db->close(); } diff --git a/src/lib/ItemList.php b/src/lib/ItemList.php index 18f71b0..4bb4c29 100644 --- a/src/lib/ItemList.php +++ b/src/lib/ItemList.php @@ -134,6 +134,22 @@ class ItemList { "/feed/items?id=$feedId&bookmarked"); } + /** + * Create an item list with items matching given search terms + * + * @param string $search The item search terms / query + * @param SQLite3 $db The database connection to use to obtain items + * @return static An item list match the given search terms + */ + public static function matchingSearch(string $search, SQLite3 $db): static { + $list = new static($db, + self::makeQuery($db, ['item.id IN (SELECT ROWID FROM item_search WHERE content MATCH :search)'], + [[':search', $search]]), 'Matching', "/search?search=$search"); + $list->showIndicators = true; + $list->displayFeed = true; + return $list; + } + /** * Render this item list */ diff --git a/src/public/search.php b/src/public/search.php new file mode 100644 index 0000000..04170c6 --- /dev/null +++ b/src/public/search.php @@ -0,0 +1,23 @@ + +

Item Search

+// TODO: search form render(); +page_foot(); +$db->close(); diff --git a/src/start.php b/src/start.php index 3b5a686..0d136fb 100644 --- a/src/start.php +++ b/src/start.php @@ -67,7 +67,8 @@ function title_bar(): void { $hasBookmarks = $bookResult && $bookResult->fetchArray(SQLITE3_NUM)[0]; echo hx_get('/feeds', 'Feeds') . ' | '; if ($hasBookmarks) echo hx_get('/?bookmarked', 'Bookmarked') . ' | '; - echo hx_get('/docs/', 'Docs') . ' | Log Off'; + echo hx_get('/search', 'Search') . ' | ' . hx_get('/docs/', 'Docs') + . ' | Log Off'; if ($_SESSION[Key::USER_EMAIL] != Security::SINGLE_USER_EMAIL) { echo " | {$_SESSION[Key::USER_EMAIL]}"; } diff --git a/src/util/search.php b/src/util/search.php new file mode 100644 index 0000000..b7430d8 --- /dev/null +++ b/src/util/search.php @@ -0,0 +1,49 @@ +query("SELECT COUNT(*) FROM sqlite_master WHERE name = 'item_ai'"); + if ($hasIndex->fetchArray(SQLITE3_NUM)[0] == 0) { + printfn('Creating search index....'); + Data::createSearchIndex($db); + } + printfn('Rebuilding search index...'); + $db->exec("INSERT INTO item_search (item_search) VALUES ('rebuild')"); + printfn(PHP_EOL . 'Search index rebuilt'); + } finally { + $db->close(); + } +}