Files
sqlite_api/handlers_functions.go

133 lines
3.5 KiB
Go

package main
import (
"context"
"database/sql"
"net/http"
"os"
"path/filepath"
"sync"
)
var (
registryDBOnce sync.Once
registryDBConn *sql.DB
registryDBErr error
)
func resolveRegistryDBPath() string {
if p := os.Getenv("FN_REGISTRY_DB"); p != "" {
return p
}
if root := os.Getenv("FN_REGISTRY_ROOT"); root != "" {
return filepath.Join(root, "registry.db")
}
return "/home/lucas/fn_registry/registry.db"
}
func openRegistryDB() (*sql.DB, error) {
registryDBOnce.Do(func() {
path := resolveRegistryDBPath()
// Read-only access — registry.db es source of truth gestionada via `fn index`.
db, err := sql.Open("sqlite3", "file:"+path+"?mode=ro&_query_only=1")
if err != nil {
registryDBErr = err
return
}
registryDBConn = db
})
return registryDBConn, registryDBErr
}
func (s *Server) handleFunctionByID(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if id == "" {
writeError(w, http.StatusBadRequest, "id is required")
return
}
db, err := openRegistryDB()
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
ctx, cancel := context.WithTimeout(r.Context(), queryTimeout)
defer cancel()
// Try functions table first.
const fnQuery = `SELECT id, name, kind, lang, domain, version, purity, signature,
description, tags, returns, returns_optional, error_type, file_path, code, documentation
FROM functions WHERE id = ?`
var (
fnID, name, kind, lang, domain, version, purity, signature string
description, tags, returns, errorType, filePath string
code, documentation string
returnsOptional bool
)
err = db.QueryRowContext(ctx, fnQuery, id).Scan(
&fnID, &name, &kind, &lang, &domain, &version, &purity, &signature,
&description, &tags, &returns, &returnsOptional, &errorType, &filePath,
&code, &documentation,
)
if err == nil {
writeJSON(w, http.StatusOK, map[string]any{
"entity": "function",
"id": fnID,
"name": name,
"kind": kind,
"lang": lang,
"domain": domain,
"version": version,
"purity": purity,
"signature": signature,
"description": description,
"tags": tags,
"returns": returns,
"returns_optional": returnsOptional,
"error_type": errorType,
"file_path": filePath,
"code": code,
"documentation": documentation,
})
return
}
if err != sql.ErrNoRows {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
// Fallback: types table.
const typeQuery = `SELECT id, name, lang, domain, version, description, tags, definition, file_path
FROM types WHERE id = ?`
var (
tID, tName, tLang, tDomain, tVersion string
tDescription, tTags, tDefinition string
tFilePath string
)
err = db.QueryRowContext(ctx, typeQuery, id).Scan(
&tID, &tName, &tLang, &tDomain, &tVersion,
&tDescription, &tTags, &tDefinition, &tFilePath,
)
if err == nil {
writeJSON(w, http.StatusOK, map[string]any{
"entity": "type",
"id": tID,
"name": tName,
"lang": tLang,
"domain": tDomain,
"version": tVersion,
"description": tDescription,
"tags": tTags,
"definition": tDefinition,
"file_path": tFilePath,
})
return
}
if err == sql.ErrNoRows {
writeError(w, http.StatusNotFound, "not_found")
return
}
writeError(w, http.StatusInternalServerError, err.Error())
}