import { FullTextSearchOptions } from "../../plug-api/plugos-syscall/fulltext.ts"; import { AsyncSQLite } from "../../plugos/sqlite/async_sqlite.ts"; import { SysCallMapping } from "../system.ts"; export async function ensureFTSTable( db: AsyncSQLite, tableName: string, ) { const result = await db.query( `SELECT name FROM sqlite_master WHERE type='table' AND name=?`, tableName, ); if (result.length === 0) { await db.execute( `CREATE VIRTUAL TABLE ${tableName} USING fts5(key, value);`, ); // console.log(`Created fts5 table ${tableName}`); } } export function fullTextSearchSyscalls( db: AsyncSQLite, tableName: string, ): SysCallMapping { return { "fulltext.index": async (_ctx, key: string, value: string) => { await db.execute(`DELETE FROM ${tableName} WHERE key = ?`, key); await db.execute( `INSERT INTO ${tableName} (key, value) VALUES (?, ?)`, key, value, ); }, "fulltext.delete": async (_ctx, key: string) => { await db.execute(`DELETE FROM ${tableName} WHERE key = ?`, key); }, "fulltext.search": async ( _ctx, phrase: string, options: FullTextSearchOptions, ) => { return ( await db.query( `SELECT key, bm25(fts) AS score, snippet(fts, 1, ?, ?, ?, ?) as snippet FROM ${tableName} WHERE value MATCH ? ORDER BY score LIMIT ?`, options.highlightPrefix || "", options.highlightPostfix || "", options.highlightEllipsis || "...", options.summaryMaxLength || 50, phrase, options.limit || 20, ) ).map((item) => ({ name: item.key, score: item.score, snippet: item.snippet, })); }, }; }