feat: schema SQLite con FTS5 y triggers de sync
Crea la base de datos del registry con: - Tabla functions con todos los campos del schema v1.0 incluyendo component - Tabla types con campos algebraicos - Tablas virtuales FTS5 para busqueda full-text sobre nombre, descripcion, tags, signature y domain - Triggers AFTER INSERT/UPDATE/DELETE para mantener FTS sincronizado - Open con WAL mode y foreign keys habilitadas - Drop y Purge para regeneracion del indice Dependencia: github.com/mattn/go-sqlite3 (requiere CGO_ENABLED=1 -tags fts5) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+153
@@ -0,0 +1,153 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
const schemaSQL = `
|
||||
CREATE TABLE IF NOT EXISTS functions (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
kind TEXT NOT NULL CHECK(kind IN ('function','pipeline','component')),
|
||||
lang TEXT NOT NULL,
|
||||
domain TEXT NOT NULL,
|
||||
version TEXT NOT NULL DEFAULT '1.0.0',
|
||||
purity TEXT NOT NULL CHECK(purity IN ('pure','impure')),
|
||||
signature TEXT NOT NULL DEFAULT '',
|
||||
description TEXT NOT NULL,
|
||||
tags TEXT NOT NULL DEFAULT '[]',
|
||||
uses_functions TEXT NOT NULL DEFAULT '[]',
|
||||
uses_types TEXT NOT NULL DEFAULT '[]',
|
||||
returns TEXT NOT NULL DEFAULT '[]',
|
||||
returns_optional INTEGER NOT NULL DEFAULT 0,
|
||||
error_type TEXT NOT NULL DEFAULT '',
|
||||
imports TEXT NOT NULL DEFAULT '[]',
|
||||
example TEXT NOT NULL DEFAULT '',
|
||||
tested INTEGER NOT NULL DEFAULT 0,
|
||||
tests TEXT NOT NULL DEFAULT '[]',
|
||||
test_file_path TEXT NOT NULL DEFAULT '',
|
||||
file_path TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
-- Component fields
|
||||
props TEXT NOT NULL DEFAULT '[]',
|
||||
emits TEXT NOT NULL DEFAULT '[]',
|
||||
has_state INTEGER,
|
||||
framework TEXT NOT NULL DEFAULT '',
|
||||
variant TEXT NOT NULL DEFAULT '[]'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS types (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
lang TEXT NOT NULL,
|
||||
domain TEXT NOT NULL,
|
||||
version TEXT NOT NULL DEFAULT '1.0.0',
|
||||
algebraic TEXT NOT NULL CHECK(algebraic IN ('product','sum')),
|
||||
definition TEXT NOT NULL DEFAULT '',
|
||||
description TEXT NOT NULL,
|
||||
tags TEXT NOT NULL DEFAULT '[]',
|
||||
uses_types TEXT NOT NULL DEFAULT '[]',
|
||||
file_path TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS functions_fts USING fts5(
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
tags,
|
||||
signature,
|
||||
domain,
|
||||
content='functions',
|
||||
content_rowid='rowid'
|
||||
);
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS types_fts USING fts5(
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
tags,
|
||||
domain,
|
||||
content='types',
|
||||
content_rowid='rowid'
|
||||
);
|
||||
|
||||
-- Triggers to keep FTS in sync
|
||||
CREATE TRIGGER IF NOT EXISTS functions_ai AFTER INSERT ON functions BEGIN
|
||||
INSERT INTO functions_fts(rowid, id, name, description, tags, signature, domain)
|
||||
VALUES (new.rowid, new.id, new.name, new.description, new.tags, new.signature, new.domain);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS functions_ad AFTER DELETE ON functions BEGIN
|
||||
INSERT INTO functions_fts(functions_fts, rowid, id, name, description, tags, signature, domain)
|
||||
VALUES ('delete', old.rowid, old.id, old.name, old.description, old.tags, old.signature, old.domain);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS functions_au AFTER UPDATE ON functions BEGIN
|
||||
INSERT INTO functions_fts(functions_fts, rowid, id, name, description, tags, signature, domain)
|
||||
VALUES ('delete', old.rowid, old.id, old.name, old.description, old.tags, old.signature, old.domain);
|
||||
INSERT INTO functions_fts(rowid, id, name, description, tags, signature, domain)
|
||||
VALUES (new.rowid, new.id, new.name, new.description, new.tags, new.signature, new.domain);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS types_ai AFTER INSERT ON types BEGIN
|
||||
INSERT INTO types_fts(rowid, id, name, description, tags, domain)
|
||||
VALUES (new.rowid, new.id, new.name, new.description, new.tags, new.domain);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS types_ad AFTER DELETE ON types BEGIN
|
||||
INSERT INTO types_fts(types_fts, rowid, id, name, description, tags, domain)
|
||||
VALUES ('delete', old.rowid, old.id, old.name, old.description, old.tags, old.domain);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS types_au AFTER UPDATE ON types BEGIN
|
||||
INSERT INTO types_fts(types_fts, rowid, id, name, description, tags, domain)
|
||||
VALUES ('delete', old.rowid, old.id, old.name, old.description, old.tags, old.domain);
|
||||
INSERT INTO types_fts(rowid, id, name, description, tags, domain)
|
||||
VALUES (new.rowid, new.id, new.name, new.description, new.tags, new.domain);
|
||||
END;
|
||||
`
|
||||
|
||||
// DB wraps a SQLite connection for the registry.
|
||||
type DB struct {
|
||||
conn *sql.DB
|
||||
path string
|
||||
}
|
||||
|
||||
// Open opens or creates the registry database at the given path.
|
||||
func Open(path string) (*DB, error) {
|
||||
dir := filepath.Dir(path)
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return nil, fmt.Errorf("creating db directory: %w", err)
|
||||
}
|
||||
|
||||
conn, err := sql.Open("sqlite3", path+"?_journal_mode=WAL&_foreign_keys=on")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening database: %w", err)
|
||||
}
|
||||
|
||||
if _, err := conn.Exec(schemaSQL); err != nil {
|
||||
conn.Close()
|
||||
return nil, fmt.Errorf("applying schema: %w", err)
|
||||
}
|
||||
|
||||
return &DB{conn: conn, path: path}, nil
|
||||
}
|
||||
|
||||
// Close closes the database connection.
|
||||
func (db *DB) Close() error {
|
||||
return db.conn.Close()
|
||||
}
|
||||
|
||||
// Drop removes the database file. Used by `fn index` to regenerate.
|
||||
func (db *DB) Drop() error {
|
||||
db.Close()
|
||||
return os.Remove(db.path)
|
||||
}
|
||||
Reference in New Issue
Block a user