auto(0129): agents_dashboard — secret_store_cpp_infra + CMakeLists register #4
@@ -0,0 +1,68 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// DetectCycle checks if adding a directed edge (from -> to) would create a cycle
|
||||
// in a directed graph stored in a SQLite table.
|
||||
// It performs BFS from toNode following edges where the filter column is non-empty.
|
||||
// If it reaches fromNode, a cycle exists.
|
||||
//
|
||||
// Parameters:
|
||||
// - conn: open *sql.DB connection
|
||||
// - table: table name containing the edges (e.g. "relations")
|
||||
// - fromCol: column name for edge source (e.g. "from_entity")
|
||||
// - toCol: column name for edge destination (e.g. "to_entity")
|
||||
// - filterCol: column name that must be non-empty for causal edges (e.g. "via"); pass "" to consider all edges
|
||||
// - fromNode: source node of the proposed new edge
|
||||
// - toNode: destination node of the proposed new edge
|
||||
func DetectCycle(conn *sql.DB, table, fromCol, toCol, filterCol, fromNode, toNode string) error {
|
||||
if fromNode == "" || toNode == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var query string
|
||||
if filterCol != "" {
|
||||
query = fmt.Sprintf("SELECT %s FROM %s WHERE %s = ? AND %s != ''", toCol, table, fromCol, filterCol)
|
||||
} else {
|
||||
query = fmt.Sprintf("SELECT %s FROM %s WHERE %s = ?", toCol, table, fromCol)
|
||||
}
|
||||
|
||||
visited := map[string]bool{}
|
||||
queue := []string{toNode}
|
||||
|
||||
for len(queue) > 0 {
|
||||
current := queue[0]
|
||||
queue = queue[1:]
|
||||
|
||||
if visited[current] {
|
||||
continue
|
||||
}
|
||||
visited[current] = true
|
||||
|
||||
if current == fromNode {
|
||||
return fmt.Errorf("cycle detected: adding edge %s -> %s would create a cycle", fromNode, toNode)
|
||||
}
|
||||
|
||||
rows, err := conn.Query(query, current)
|
||||
if err != nil {
|
||||
return fmt.Errorf("querying %s for cycle detection: %w", table, err)
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
var next string
|
||||
if err := rows.Scan(&next); err != nil {
|
||||
rows.Close()
|
||||
return err
|
||||
}
|
||||
if !visited[next] {
|
||||
queue = append(queue, next)
|
||||
}
|
||||
}
|
||||
rows.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: detect_cycle
|
||||
kind: function
|
||||
lang: go
|
||||
domain: core
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "func DetectCycle(conn *sql.DB, table, fromCol, toCol, filterCol, fromNode, toNode string) error"
|
||||
description: "Detecta ciclos en un grafo dirigido almacenado en SQLite usando BFS antes de insertar una arista."
|
||||
tags: [graph, cycle, bfs, sqlite, validation]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: ["database/sql"]
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "functions/core/detect_cycle.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
// Verificar si agregar A -> B crearia un ciclo en la tabla "relations"
|
||||
err := DetectCycle(db, "relations", "from_entity", "to_entity", "via", "A", "B")
|
||||
if err != nil {
|
||||
// ciclo detectado
|
||||
}
|
||||
|
||||
// Sin filtro — considerar todas las aristas
|
||||
err = DetectCycle(db, "edges", "source", "target", "", "X", "Y")
|
||||
```
|
||||
|
||||
## Notas
|
||||
|
||||
Usa BFS desde toNode siguiendo aristas existentes. Si alcanza fromNode, la nueva arista crearia un ciclo. El parametro filterCol permite ignorar aristas semanticas (no causales) — pasar "" para considerar todas.
|
||||
@@ -0,0 +1,7 @@
|
||||
package core
|
||||
|
||||
// GenerateID builds a canonical ID from name, lang, and domain.
|
||||
// Format: {name}_{lang}_{domain}
|
||||
func GenerateID(name, lang, domain string) string {
|
||||
return name + "_" + lang + "_" + domain
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: generate_id
|
||||
kind: function
|
||||
lang: go
|
||||
domain: core
|
||||
version: "1.0.0"
|
||||
purity: pure
|
||||
signature: "func GenerateID(name, lang, domain string) string"
|
||||
description: "Genera un ID canonico determinista a partir de nombre, lenguaje y dominio."
|
||||
tags: [id, naming, deterministic]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
imports: []
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "functions/core/generate_id.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
id := GenerateID("filter_slice", "go", "core")
|
||||
// id = "filter_slice_go_core"
|
||||
```
|
||||
|
||||
## Notas
|
||||
|
||||
Funcion pura sin dependencias. Util para cualquier sistema que necesite IDs compuestos deterministas a partir de componentes con nombre.
|
||||
@@ -0,0 +1,58 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var rewriteFieldPattern = regexp.MustCompile(`\b([a-zA-Z_][a-zA-Z0-9_]*)\b`)
|
||||
|
||||
var rewriteSQLKeywords = map[string]bool{
|
||||
"AND": true, "OR": true, "NOT": true, "IS": true, "NULL": true,
|
||||
"IN": true, "BETWEEN": true, "LIKE": true, "GLOB": true,
|
||||
"TRUE": true, "FALSE": true, "CASE": true, "WHEN": true,
|
||||
"THEN": true, "ELSE": true, "END": true, "SELECT": true,
|
||||
"FROM": true, "WHERE": true, "AS": true, "CAST": true,
|
||||
}
|
||||
|
||||
var rewriteSQLFunctions = map[string]bool{
|
||||
"json_extract": true, "datetime": true, "now": true,
|
||||
"abs": true, "avg": true, "count": true, "max": true, "min": true,
|
||||
"sum": true, "total": true, "length": true, "typeof": true,
|
||||
"coalesce": true, "ifnull": true, "nullif": true,
|
||||
"upper": true, "lower": true, "trim": true, "replace": true,
|
||||
"substr": true, "instr": true, "round": true,
|
||||
}
|
||||
|
||||
// RewriteRule transforms a rule expression so that bare field names become
|
||||
// json_extract calls on a given JSON column.
|
||||
// For example, with column "metadata":
|
||||
//
|
||||
// "price > 100 AND status IS NOT NULL"
|
||||
//
|
||||
// becomes:
|
||||
//
|
||||
// "json_extract(metadata, '$.price') > 100 AND json_extract(metadata, '$.status') IS NOT NULL"
|
||||
//
|
||||
// If the rule already contains json_extract, it is returned as-is.
|
||||
// SQL keywords and common SQL functions are preserved.
|
||||
func RewriteRule(rule, jsonColumn string) string {
|
||||
if strings.Contains(rule, "json_extract") {
|
||||
return rule
|
||||
}
|
||||
|
||||
return rewriteFieldPattern.ReplaceAllStringFunc(rule, func(match string) string {
|
||||
upper := strings.ToUpper(match)
|
||||
if rewriteSQLKeywords[upper] {
|
||||
return match
|
||||
}
|
||||
if rewriteSQLFunctions[strings.ToLower(match)] {
|
||||
return match
|
||||
}
|
||||
if match[0] >= '0' && match[0] <= '9' {
|
||||
return match
|
||||
}
|
||||
return fmt.Sprintf("json_extract(%s, '$.%s')", jsonColumn, match)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: rewrite_rule
|
||||
kind: function
|
||||
lang: go
|
||||
domain: core
|
||||
version: "1.0.0"
|
||||
purity: pure
|
||||
signature: "func RewriteRule(rule, jsonColumn string) string"
|
||||
description: "Reescribe campos bare en una expresion SQL a llamadas json_extract sobre una columna JSON de SQLite."
|
||||
tags: [sql, json, sqlite, rewrite, assertion]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
imports: ["regexp"]
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "functions/core/rewrite_rule.go"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```go
|
||||
out := RewriteRule("price > 100 AND status IS NOT NULL", "metadata")
|
||||
// out = "json_extract(metadata, '$.price') > 100 AND json_extract(metadata, '$.status') IS NOT NULL"
|
||||
|
||||
// Si ya tiene json_extract, no modifica nada
|
||||
out = RewriteRule("json_extract(data, '$.x') > 0", "data")
|
||||
// out = "json_extract(data, '$.x') > 0"
|
||||
```
|
||||
|
||||
## Notas
|
||||
|
||||
Funcion pura. Preserva keywords SQL y funciones SQLite conocidas. Util para construir queries dinamicas sobre columnas JSON en SQLite sin que el usuario tenga que escribir json_extract manualmente.
|
||||
Reference in New Issue
Block a user