Class: Msnav::Graph
- Inherits:
-
Object
- Object
- Msnav::Graph
- Defined in:
- lib/msnav/graph.rb
Overview
In-memory view of the coderag code graph (nodes/edges tables), with the same secondary indexes coderag builds: by-kind, per-(service, file) node lists, and per-file line-interval lists for covering-symbol lookup.
Node data and edge data are the JSON hashes coderag persisted (string keys); an edge's "kind" column is merged back into its data hash, exactly like CodeGraph.load does in Python.
Instance Attribute Summary collapse
-
#nodes ⇒ Object
readonly
Returns the value of attribute nodes.
Class Method Summary collapse
-
.load(store, workspace_root = nil) ⇒ Object
Load the graph and re-anchor service roots when the same workspace is mounted at a different path than at index time (host <-> container).
Instance Method Summary collapse
-
#covering_symbol(service, file, line) ⇒ Object
Smallest node whose line span covers
line(1-based) in the file's interval list. - #endpoints(service = nil) ⇒ Object
- #has_node?(node_id) ⇒ Boolean
-
#in_edges(node_id) ⇒ Object
Incoming [src, edge_data] pairs (cross-service references).
-
#initialize(nodes, out_edges, in_edges) ⇒ Graph
constructor
A new instance of Graph.
- #node(node_id) ⇒ Object
- #nodes_in_file(service, file) ⇒ Object
- #nodes_of_kind(kind) ⇒ Object
-
#out(node_id, kinds = nil) ⇒ Object
Outgoing [dst, edge_data] pairs, optionally filtered to edge kinds.
-
#rebase_roots(stored_ws, workspace_root) ⇒ Object
Re-anchor service roots from the workspace root stored at index time to WORKSPACE_ROOT.
- #services ⇒ Object
Constructor Details
#initialize(nodes, out_edges, in_edges) ⇒ Graph
Returns a new instance of Graph.
46 47 48 49 50 51 |
# File 'lib/msnav/graph.rb', line 46 def initialize(nodes, out_edges, in_edges) @nodes = nodes @out_edges = out_edges @in_edges = in_edges build_indexes end |
Instance Attribute Details
#nodes ⇒ Object (readonly)
Returns the value of attribute nodes.
14 15 16 |
# File 'lib/msnav/graph.rb', line 14 def nodes @nodes end |
Class Method Details
.load(store, workspace_root = nil) ⇒ Object
Load the graph and re-anchor service roots when the same workspace is mounted at a different path than at index time (host <-> container). Each root is rebased only if the rebased directory actually exists — a container that mounts only the data dir keeps the stored host paths and serves them verbatim (the service-scoped devcontainer flow).
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/msnav/graph.rb', line 21 def self.load(store, workspace_root = nil) nodes = {} out_edges = Hash.new { |h, k| h[k] = [] } in_edges = Hash.new { |h, k| h[k] = [] } stored_ws = nil store.with_conn do |db| db.execute("SELECT id, data FROM nodes") do |id, data| nodes[id] = JSON.parse(data) end db.execute("SELECT src, dst, kind, data FROM edges") do |src, dst, kind, data| edge = JSON.parse(data) edge["kind"] = kind nodes[src] ||= {} # edges may reference nodes with no attributes nodes[dst] ||= {} out_edges[src] << [dst, edge] in_edges[dst] << [src, edge] end row = db.get_first_row("SELECT value FROM meta WHERE key='workspace_root'") stored_ws = row && row[0] end graph = new(nodes, out_edges, in_edges) graph.rebase_roots(stored_ws, workspace_root.to_s) if workspace_root graph end |
Instance Method Details
#covering_symbol(service, file, line) ⇒ Object
Smallest node whose line span covers line (1-based) in the file's
interval list. Ties break toward the later start line, matching the
Python bisect walk.
94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/msnav/graph.rb', line 94 def covering_symbol(service, file, line) spans = @intervals[[service, file]] || [] best = nil spans.reverse_each do |start_line, end_line, node_id| next if start_line > line next if end_line < line size = end_line - start_line best = [size, node_id] if best.nil? || size < best[0] end best && best[1] end |
#endpoints(service = nil) ⇒ Object
85 86 87 88 89 |
# File 'lib/msnav/graph.rb', line 85 def endpoints(service = nil) nodes_of_kind("endpoint").select do |_id, data| service.nil? || data["service"] == service end end |
#has_node?(node_id) ⇒ Boolean
57 58 59 |
# File 'lib/msnav/graph.rb', line 57 def has_node?(node_id) @nodes.key?(node_id) end |
#in_edges(node_id) ⇒ Object
Incoming [src, edge_data] pairs (cross-service references).
69 70 71 |
# File 'lib/msnav/graph.rb', line 69 def in_edges(node_id) @in_edges[node_id] || [] end |
#node(node_id) ⇒ Object
53 54 55 |
# File 'lib/msnav/graph.rb', line 53 def node(node_id) @nodes[node_id] end |
#nodes_in_file(service, file) ⇒ Object
77 78 79 |
# File 'lib/msnav/graph.rb', line 77 def nodes_in_file(service, file) (@by_service_file[[service, file]] || []).map { |id| [id, @nodes[id]] } end |
#nodes_of_kind(kind) ⇒ Object
73 74 75 |
# File 'lib/msnav/graph.rb', line 73 def nodes_of_kind(kind) (@by_kind[kind] || []).map { |id| [id, @nodes[id]] } end |
#out(node_id, kinds = nil) ⇒ Object
Outgoing [dst, edge_data] pairs, optionally filtered to edge kinds.
62 63 64 65 66 |
# File 'lib/msnav/graph.rb', line 62 def out(node_id, kinds = nil) edges = @out_edges[node_id] || [] return edges if kinds.nil? edges.select { |_dst, data| kinds.include?(data["kind"]) } end |
#rebase_roots(stored_ws, workspace_root) ⇒ Object
Re-anchor service roots from the workspace root stored at index time to WORKSPACE_ROOT. No-op when they match, the meta key is missing, or the rebased directory does not exist.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/msnav/graph.rb', line 109 def rebase_roots(stored_ws, workspace_root) ws = File.(workspace_root) return if stored_ws.nil? || stored_ws.empty? return if File.(stored_ws) == ws stored = Pathname.new(File.(stored_ws)) services.each do |_id, data| root = data["root"] next if root.nil? || root.empty? begin rel = Pathname.new(File.(root)).relative_path_from(stored).to_s rescue ArgumentError next end next if rel.start_with?("..") candidate = rel == "." ? ws : File.join(ws, rel) data["root"] = candidate if File.directory?(candidate) end build_indexes end |
#services ⇒ Object
81 82 83 |
# File 'lib/msnav/graph.rb', line 81 def services nodes_of_kind("service") end |