spb/drive Public
SPB Drive — self-hosted personal cloud drive (files, previews, sharing) on the MacLustr cluster.
JavaScript 82.7%
CSS 10.6%
Nunjucks 3.6%
Shell 1.8%
SQL 1.3%
1/**2 * ─────────────────────────────────────────────3 * SPB Drive — Personal Cloud Drive4 * ─────────────────────────────────────────────5 * Author : Simon-Pierre Boucher6 * Contact : contact@spboucher.ai7 * File : src/search/index-sync.mjs8 * Purpose : Keep the FTS5 index in sync with node names/tags/content9 * License : MIT © Simon-Pierre Boucher10 * ─────────────────────────────────────────────11 */1213import { getDb } from '../db/db.mjs';1415/** Current tag names for a node, space-joined for the FTS tags column. */16function tagsText(nodeId) {17 return getDb()18 .prepare(19 `SELECT GROUP_CONCAT(t.name, ' ') AS tags FROM node_tags nt20 JOIN tags t ON t.id = nt.tag_id WHERE nt.node_id = ?`,21 )22 .get(nodeId)?.tags ?? '';23}2425/** Insert or refresh the FTS row for a node's name (keeps existing content). */26export function upsertFtsName(nodeId, name) {27 const db = getDb();28 const existing = db.prepare('SELECT content FROM fts WHERE rowid = ?').get(nodeId);29 db.prepare('DELETE FROM fts WHERE rowid = ?').run(nodeId);30 db.prepare('INSERT INTO fts (rowid, name, tags, content) VALUES (?, ?, ?, ?)').run(31 nodeId, name, tagsText(nodeId), existing?.content ?? '',32 );33}3435/** Refresh only the tags column for a node. */36export function updateFtsTags(nodeId) {37 const db = getDb();38 const node = db.prepare('SELECT name FROM nodes WHERE id = ?').get(nodeId);39 if (node) upsertFtsName(nodeId, node.name);40}4142/** Store extracted text content for a node (search-inside-files). */43export function setFtsContent(nodeId, content, contentSha) {44 const db = getDb();45 const node = db.prepare('SELECT name FROM nodes WHERE id = ?').get(nodeId);46 if (!node) return;47 db.prepare('DELETE FROM fts WHERE rowid = ?').run(nodeId);48 db.prepare('INSERT INTO fts (rowid, name, tags, content) VALUES (?, ?, ?, ?)').run(49 nodeId, node.name, tagsText(nodeId), (content ?? '').slice(0, 1_000_000),50 );51 db.prepare(52 `INSERT INTO fts_state (node_id, content_sha) VALUES (?, ?)53 ON CONFLICT(node_id) DO UPDATE SET content_sha = excluded.content_sha`,54 ).run(nodeId, contentSha ?? null);55}5657/** Remove a node from the index entirely. */58export function deleteFtsEntry(nodeId) {59 const db = getDb();60 db.prepare('DELETE FROM fts WHERE rowid = ?').run(nodeId);61 db.prepare('DELETE FROM fts_state WHERE node_id = ?').run(nodeId);62}63