chore: import upstream snapshot with attribution
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/zzet/gortex/internal/graph"
|
||||
)
|
||||
|
||||
// RebuildStats summarises a RebuildTablesFromStringRegistry pass. All
|
||||
// counts are net (created — already-present). EmittersLinked counts the
|
||||
// unique (caller, table) pairs that produced an EdgeQueries edge.
|
||||
type RebuildStats struct {
|
||||
StringsVisited int `json:"strings_visited"`
|
||||
TablesCreated int `json:"tables_created"`
|
||||
ColumnsCreated int `json:"columns_created"`
|
||||
QueryEdges int `json:"query_edges_created"`
|
||||
ReadColEdges int `json:"reads_col_edges_created"`
|
||||
WriteColEdges int `json:"writes_col_edges_created"`
|
||||
EmittersLinked int `json:"emitters_linked"`
|
||||
Skipped int `json:"skipped"`
|
||||
}
|
||||
|
||||
// RebuildTablesFromStringRegistry is the short-circuit: rederive
|
||||
// the KindTable / KindColumn / EdgeQueries / EdgeReadsCol /
|
||||
// EdgeWritesCol layer from the KindString context="sql" registry
|
||||
// already present in g, without re-parsing any source file. Idempotent
|
||||
// — nodes and edges are deduped via graph.AddNode / AddEdge semantics,
|
||||
// so running it twice produces the same graph.
|
||||
//
|
||||
// For each KindString context="sql" node:
|
||||
//
|
||||
// - Re-extract tables and columns from node.Name (the verbatim
|
||||
// query) using the canonical ExtractTables / ExtractColumns
|
||||
// parsers — the same shape the source-time extractor uses.
|
||||
// - For every emitter (EdgeEmits.From → KindString), wire
|
||||
// EdgeQueries to each derived KindTable and EdgeReadsCol /
|
||||
// EdgeWritesCol to each derived KindColumn.
|
||||
//
|
||||
// Dialect is taken from Meta["dialect"] when present (set by the Go
|
||||
// SQL extractor) and falls back to "generic". Origin on rebuilt edges
|
||||
// is text_matched (same tier the source-time extractor uses for
|
||||
// regex-derived SQL).
|
||||
//
|
||||
// Returns counts for telemetry; rebuilt edges idempotently replace
|
||||
// any existing edges with the same edgeKey, so a second call after
|
||||
// the first reports tablesCreated=0, emittersLinked=0.
|
||||
func RebuildTablesFromStringRegistry(g graph.Store) RebuildStats {
|
||||
if g == nil {
|
||||
return RebuildStats{}
|
||||
}
|
||||
var stats RebuildStats
|
||||
// Snapshot the node set to avoid mutation-during-iteration; we
|
||||
// append KindTable / KindColumn nodes below.
|
||||
nodes := g.AllNodes()
|
||||
// Track per-call counts of new node/edge insertions; we infer
|
||||
// "created" by checking presence before AddNode / AddEdge.
|
||||
preExistingTables := make(map[string]struct{})
|
||||
preExistingCols := make(map[string]struct{})
|
||||
for _, n := range nodes {
|
||||
if n == nil {
|
||||
continue
|
||||
}
|
||||
switch n.Kind {
|
||||
case graph.KindTable:
|
||||
preExistingTables[n.ID] = struct{}{}
|
||||
case graph.KindColumn:
|
||||
preExistingCols[n.ID] = struct{}{}
|
||||
}
|
||||
}
|
||||
// EdgeQueries / EdgeReadsCol / EdgeWritesCol dedup tracker.
|
||||
// Seeded from the live graph so a re-run on an already-rebuilt
|
||||
// graph reports zero new edges (graph.AddEdge is idempotent by
|
||||
// edgeKey, but the stats counters live in this function so they
|
||||
// need to know what was already there).
|
||||
type edgeKey struct {
|
||||
from, to string
|
||||
kind graph.EdgeKind
|
||||
}
|
||||
seenEdges := make(map[edgeKey]struct{})
|
||||
for _, n := range nodes {
|
||||
if n == nil {
|
||||
continue
|
||||
}
|
||||
if n.Kind != graph.KindTable && n.Kind != graph.KindColumn {
|
||||
continue
|
||||
}
|
||||
for _, e := range g.GetInEdges(n.ID) {
|
||||
if e == nil {
|
||||
continue
|
||||
}
|
||||
switch e.Kind {
|
||||
case graph.EdgeQueries, graph.EdgeReadsCol, graph.EdgeWritesCol:
|
||||
seenEdges[edgeKey{from: e.From, to: e.To, kind: e.Kind}] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, n := range nodes {
|
||||
if n == nil || n.Kind != graph.KindString {
|
||||
continue
|
||||
}
|
||||
if ctx, _ := n.Meta["context"].(string); ctx != "sql" {
|
||||
continue
|
||||
}
|
||||
query := n.Name
|
||||
if query == "" {
|
||||
if v, ok := n.Meta["value"].(string); ok {
|
||||
query = v
|
||||
}
|
||||
}
|
||||
if query == "" {
|
||||
stats.Skipped++
|
||||
continue
|
||||
}
|
||||
stats.StringsVisited++
|
||||
dialect, _ := n.Meta["dialect"].(string)
|
||||
if dialect == "" {
|
||||
dialect = "generic"
|
||||
}
|
||||
tables := ExtractTables(query)
|
||||
columns := ExtractColumns(query)
|
||||
if len(tables) == 0 {
|
||||
stats.Skipped++
|
||||
continue
|
||||
}
|
||||
// Collect emitters from EdgeEmits to this KindString.
|
||||
emitters := make([]string, 0, 4)
|
||||
seenEmitter := make(map[string]struct{}, 4)
|
||||
for _, e := range g.GetInEdges(n.ID) {
|
||||
if e == nil || e.Kind != graph.EdgeEmits {
|
||||
continue
|
||||
}
|
||||
if _, dup := seenEmitter[e.From]; dup {
|
||||
continue
|
||||
}
|
||||
seenEmitter[e.From] = struct{}{}
|
||||
emitters = append(emitters, e.From)
|
||||
}
|
||||
// Stable ordering — emitter snapshots are otherwise shard-
|
||||
// order-dependent, which makes test assertions racy.
|
||||
sort.Strings(emitters)
|
||||
// Ensure KindTable nodes.
|
||||
tableNodes := make([]struct {
|
||||
id string
|
||||
ref TableRef
|
||||
added bool
|
||||
}, 0, len(tables))
|
||||
for _, ref := range tables {
|
||||
id := TableNodeID(dialect, ref.Schema, ref.Table)
|
||||
if _, exists := preExistingTables[id]; !exists {
|
||||
meta := map[string]any{
|
||||
"table": ref.Table,
|
||||
"dialect": dialect,
|
||||
}
|
||||
if ref.Schema != "" {
|
||||
meta["schema"] = ref.Schema
|
||||
}
|
||||
g.AddNode(&graph.Node{
|
||||
ID: id,
|
||||
Kind: graph.KindTable,
|
||||
Name: ref.Table,
|
||||
FilePath: n.FilePath,
|
||||
Language: "sql",
|
||||
Meta: meta,
|
||||
})
|
||||
preExistingTables[id] = struct{}{}
|
||||
stats.TablesCreated++
|
||||
tableNodes = append(tableNodes, struct {
|
||||
id string
|
||||
ref TableRef
|
||||
added bool
|
||||
}{id, ref, true})
|
||||
} else {
|
||||
tableNodes = append(tableNodes, struct {
|
||||
id string
|
||||
ref TableRef
|
||||
added bool
|
||||
}{id, ref, false})
|
||||
}
|
||||
}
|
||||
// Ensure KindColumn nodes.
|
||||
colNodes := make([]struct {
|
||||
id string
|
||||
ref ColumnRef
|
||||
}, 0, len(columns))
|
||||
for _, col := range columns {
|
||||
id := ColumnNodeID(dialect, col.Schema, col.Table, col.Column)
|
||||
if _, exists := preExistingCols[id]; !exists {
|
||||
meta := map[string]any{
|
||||
"table": col.Table,
|
||||
"column": col.Column,
|
||||
"dialect": dialect,
|
||||
}
|
||||
if col.Schema != "" {
|
||||
meta["schema"] = col.Schema
|
||||
}
|
||||
g.AddNode(&graph.Node{
|
||||
ID: id,
|
||||
Kind: graph.KindColumn,
|
||||
Name: col.Column,
|
||||
FilePath: n.FilePath,
|
||||
Language: "sql",
|
||||
Meta: meta,
|
||||
})
|
||||
preExistingCols[id] = struct{}{}
|
||||
stats.ColumnsCreated++
|
||||
}
|
||||
colNodes = append(colNodes, struct {
|
||||
id string
|
||||
ref ColumnRef
|
||||
}{id, col})
|
||||
}
|
||||
// Wire emitters → tables / columns.
|
||||
for _, emitter := range emitters {
|
||||
for _, t := range tableNodes {
|
||||
k := edgeKey{from: emitter, to: t.id, kind: graph.EdgeQueries}
|
||||
if _, dup := seenEdges[k]; dup {
|
||||
continue
|
||||
}
|
||||
seenEdges[k] = struct{}{}
|
||||
g.AddEdge(&graph.Edge{
|
||||
From: emitter,
|
||||
To: t.id,
|
||||
Kind: graph.EdgeQueries,
|
||||
FilePath: n.FilePath,
|
||||
Origin: graph.OriginTextMatched,
|
||||
Meta: map[string]any{
|
||||
"op": t.ref.Op,
|
||||
"source": "string_registry",
|
||||
},
|
||||
})
|
||||
stats.QueryEdges++
|
||||
stats.EmittersLinked++
|
||||
}
|
||||
for _, c := range colNodes {
|
||||
kind := graph.EdgeReadsCol
|
||||
if c.ref.Op == "write" {
|
||||
kind = graph.EdgeWritesCol
|
||||
}
|
||||
k := edgeKey{from: emitter, to: c.id, kind: kind}
|
||||
if _, dup := seenEdges[k]; dup {
|
||||
continue
|
||||
}
|
||||
seenEdges[k] = struct{}{}
|
||||
g.AddEdge(&graph.Edge{
|
||||
From: emitter,
|
||||
To: c.id,
|
||||
Kind: kind,
|
||||
FilePath: n.FilePath,
|
||||
Origin: graph.OriginTextMatched,
|
||||
Meta: map[string]any{
|
||||
"source": "string_registry",
|
||||
},
|
||||
})
|
||||
if kind == graph.EdgeReadsCol {
|
||||
stats.ReadColEdges++
|
||||
} else {
|
||||
stats.WriteColEdges++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stats
|
||||
}
|
||||
Reference in New Issue
Block a user