|
1
|
""" |
|
2
|
Cypher query templates for navegador. |
|
3
|
|
|
4
|
Parameters passed as $name are substituted by FalkorDB at query time. |
|
5
|
Optional file_path filtering: when file_path is "" the WHERE clause is omitted |
|
6
|
so callers/callees/references work across the whole graph by name alone. |
|
7
|
""" |
|
8
|
|
|
9
|
# ── Code: file contents ─────────────────────────────────────────────────────── |
|
10
|
|
|
11
|
FILE_CONTENTS = """ |
|
12
|
MATCH (f:File {path: $path})-[:CONTAINS]->(n) |
|
13
|
RETURN labels(n)[0] AS type, n.name AS name, n.line_start AS line, |
|
14
|
n.docstring AS docstring, n.signature AS signature |
|
15
|
ORDER BY n.line_start |
|
16
|
""" |
|
17
|
|
|
18
|
DIRECT_IMPORTS = """ |
|
19
|
MATCH (n {file_path: $file_path, name: $name})-[:IMPORTS]->(dep) |
|
20
|
RETURN labels(dep)[0] AS type, dep.name AS name, dep.file_path AS file_path |
|
21
|
""" |
|
22
|
|
|
23
|
# ── Code: call graph ────────────────────────────────────────────────────────── |
|
24
|
|
|
25
|
# file_path is optional — if empty, match by name only across all files |
|
26
|
CALLERS = """ |
|
27
|
MATCH (caller)-[:CALLS*1..$depth]->(fn) |
|
28
|
WHERE fn.name = $name AND ($file_path = '' OR fn.file_path = $file_path) |
|
29
|
RETURN DISTINCT labels(caller)[0] AS type, caller.name AS name, |
|
30
|
caller.file_path AS file_path, caller.line_start AS line |
|
31
|
""" |
|
32
|
|
|
33
|
CALLEES = """ |
|
34
|
MATCH (fn)-[:CALLS*1..$depth]->(callee) |
|
35
|
WHERE fn.name = $name AND ($file_path = '' OR fn.file_path = $file_path) |
|
36
|
RETURN DISTINCT labels(callee)[0] AS type, callee.name AS name, |
|
37
|
callee.file_path AS file_path, callee.line_start AS line |
|
38
|
""" |
|
39
|
|
|
40
|
# ── Code: class hierarchy ───────────────────────────────────────────────────── |
|
41
|
|
|
42
|
CLASS_HIERARCHY = """ |
|
43
|
MATCH (c:Class {name: $name})-[:INHERITS*]->(parent) |
|
44
|
RETURN parent.name AS name, parent.file_path AS file_path |
|
45
|
""" |
|
46
|
|
|
47
|
SUBCLASSES = """ |
|
48
|
MATCH (child:Class)-[:INHERITS*]->(c:Class {name: $name}) |
|
49
|
RETURN child.name AS name, child.file_path AS file_path |
|
50
|
""" |
|
51
|
|
|
52
|
# ── Code: decorators ───────────────────────────────────────────────────────── |
|
53
|
|
|
54
|
# All functions/methods carrying a given decorator |
|
55
|
DECORATED_BY = """ |
|
56
|
MATCH (d:Decorator {name: $decorator_name})-[:DECORATES]->(n) |
|
57
|
RETURN labels(n)[0] AS type, n.name AS name, n.file_path AS file_path, |
|
58
|
n.line_start AS line |
|
59
|
""" |
|
60
|
|
|
61
|
# All decorators on a given function/method |
|
62
|
DECORATORS_FOR = """ |
|
63
|
MATCH (d:Decorator)-[:DECORATES]->(n) |
|
64
|
WHERE n.name = $name AND ($file_path = '' OR n.file_path = $file_path) |
|
65
|
RETURN d.name AS decorator, d.file_path AS file_path, d.line_start AS line |
|
66
|
""" |
|
67
|
|
|
68
|
# ── Code: references ───────────────────────────────────────────────────────── |
|
69
|
|
|
70
|
REFERENCES_TO = """ |
|
71
|
MATCH (src)-[:REFERENCES]->(tgt) |
|
72
|
WHERE tgt.name = $name AND ($file_path = '' OR tgt.file_path = $file_path) |
|
73
|
RETURN DISTINCT labels(src)[0] AS type, src.name AS name, |
|
74
|
src.file_path AS file_path, src.line_start AS line |
|
75
|
""" |
|
76
|
|
|
77
|
# ── Universal: neighbor traversal ──────────────────────────────────────────── |
|
78
|
|
|
79
|
# All nodes reachable from a named node within N hops (any edge type) |
|
80
|
NEIGHBORS = """ |
|
81
|
MATCH (root) |
|
82
|
WHERE root.name = $name AND ($file_path = '' OR root.file_path = $file_path) |
|
83
|
OPTIONAL MATCH (root)-[r*1..$depth]-(neighbor) |
|
84
|
RETURN DISTINCT |
|
85
|
labels(root)[0] AS root_type, |
|
86
|
root.name AS root_name, |
|
87
|
labels(neighbor)[0] AS neighbor_type, |
|
88
|
neighbor.name AS neighbor_name, |
|
89
|
neighbor.file_path AS neighbor_file_path |
|
90
|
""" |
|
91
|
|
|
92
|
# ── Universal: search ───────────────────────────────────────────────────────── |
|
93
|
|
|
94
|
# Search code symbols by name substring |
|
95
|
SYMBOL_SEARCH = """ |
|
96
|
MATCH (n) |
|
97
|
WHERE (n:Function OR n:Class OR n:Method) AND n.name CONTAINS $query |
|
98
|
RETURN labels(n)[0] AS type, n.name AS name, n.file_path AS file_path, |
|
99
|
n.line_start AS line, n.docstring AS docstring |
|
100
|
LIMIT $limit |
|
101
|
""" |
|
102
|
|
|
103
|
# Search code symbols by docstring content |
|
104
|
DOCSTRING_SEARCH = """ |
|
105
|
MATCH (n) |
|
106
|
WHERE (n:Function OR n:Class OR n:Method) |
|
107
|
AND n.docstring IS NOT NULL |
|
108
|
AND toLower(n.docstring) CONTAINS toLower($query) |
|
109
|
RETURN labels(n)[0] AS type, n.name AS name, n.file_path AS file_path, |
|
110
|
n.line_start AS line, n.docstring AS docstring |
|
111
|
LIMIT $limit |
|
112
|
""" |
|
113
|
|
|
114
|
# Search knowledge layer (concepts, rules, decisions, wiki) by name or description |
|
115
|
KNOWLEDGE_SEARCH = """ |
|
116
|
MATCH (n) |
|
117
|
WHERE (n:Concept OR n:Rule OR n:Decision OR n:WikiPage) |
|
118
|
AND (toLower(n.name) CONTAINS toLower($query) |
|
119
|
OR (n.description IS NOT NULL AND toLower(n.description) CONTAINS toLower($query))) |
|
120
|
RETURN labels(n)[0] AS type, n.name AS name, n.description AS description, |
|
121
|
n.domain AS domain, n.status AS status |
|
122
|
LIMIT $limit |
|
123
|
""" |
|
124
|
|
|
125
|
# Search everything — code + knowledge — in one query |
|
126
|
GLOBAL_SEARCH = """ |
|
127
|
MATCH (n) |
|
128
|
WHERE (n:Function OR n:Class OR n:Method OR n:Concept OR n:Rule OR n:Decision OR n:WikiPage) |
|
129
|
AND (toLower(n.name) CONTAINS toLower($query) |
|
130
|
OR (n.docstring IS NOT NULL AND toLower(n.docstring) CONTAINS toLower($query)) |
|
131
|
OR (n.description IS NOT NULL AND toLower(n.description) CONTAINS toLower($query))) |
|
132
|
RETURN labels(n)[0] AS type, n.name AS name, |
|
133
|
coalesce(n.file_path, '') AS file_path, |
|
134
|
coalesce(n.docstring, n.description, '') AS summary, |
|
135
|
n.line_start AS line |
|
136
|
LIMIT $limit |
|
137
|
""" |
|
138
|
|
|
139
|
# ── Knowledge: domain ───────────────────────────────────────────────────────── |
|
140
|
|
|
141
|
DOMAIN_CONTENTS = """ |
|
142
|
MATCH (n)-[:BELONGS_TO]->(d:Domain {name: $domain}) |
|
143
|
RETURN labels(n)[0] AS type, n.name AS name, |
|
144
|
coalesce(n.file_path, '') AS file_path, |
|
145
|
coalesce(n.docstring, n.description, '') AS summary |
|
146
|
ORDER BY labels(n)[0], n.name |
|
147
|
""" |
|
148
|
|
|
149
|
# ── Knowledge: concept context ─────────────────────────────────────────────── |
|
150
|
|
|
151
|
CONCEPT_CONTEXT = """ |
|
152
|
MATCH (c:Concept {name: $name}) |
|
153
|
OPTIONAL MATCH (c)-[:RELATED_TO]-(related:Concept) |
|
154
|
OPTIONAL MATCH (rule:Rule)-[:GOVERNS]->(c) |
|
155
|
OPTIONAL MATCH (wiki:WikiPage)-[:DOCUMENTS]->(c) |
|
156
|
OPTIONAL MATCH (impl)-[:IMPLEMENTS]->(c) |
|
157
|
OPTIONAL MATCH (c)-[:BELONGS_TO]->(domain:Domain) |
|
158
|
RETURN |
|
159
|
c.name AS name, c.description AS description, |
|
160
|
c.status AS status, c.domain AS domain, |
|
161
|
collect(DISTINCT related.name) AS related_concepts, |
|
162
|
collect(DISTINCT rule.name) AS governing_rules, |
|
163
|
collect(DISTINCT wiki.name) AS wiki_pages, |
|
164
|
collect(DISTINCT impl.name) AS implemented_by, |
|
165
|
collect(DISTINCT domain.name) AS domains |
|
166
|
""" |
|
167
|
|
|
168
|
# ── Explain: full picture for any named node ────────────────────────────────── |
|
169
|
|
|
170
|
# All outbound relationships from a node |
|
171
|
OUTBOUND = """ |
|
172
|
MATCH (n)-[r]->(neighbor) |
|
173
|
WHERE n.name = $name AND ($file_path = '' OR n.file_path = $file_path) |
|
174
|
RETURN type(r) AS rel, labels(neighbor)[0] AS neighbor_type, |
|
175
|
neighbor.name AS neighbor_name, |
|
176
|
coalesce(neighbor.file_path, '') AS neighbor_file_path |
|
177
|
ORDER BY rel, neighbor_name |
|
178
|
""" |
|
179
|
|
|
180
|
# All inbound relationships to a node |
|
181
|
INBOUND = """ |
|
182
|
MATCH (neighbor)-[r]->(n) |
|
183
|
WHERE n.name = $name AND ($file_path = '' OR n.file_path = $file_path) |
|
184
|
RETURN type(r) AS rel, labels(neighbor)[0] AS neighbor_type, |
|
185
|
neighbor.name AS neighbor_name, |
|
186
|
coalesce(neighbor.file_path, '') AS neighbor_file_path |
|
187
|
ORDER BY rel, neighbor_name |
|
188
|
""" |
|
189
|
|
|
190
|
# ── Knowledge: decision rationale ───────────────────────────────────────────── |
|
191
|
|
|
192
|
DECISION_RATIONALE = """ |
|
193
|
MATCH (d:Decision {name: $name}) |
|
194
|
OPTIONAL MATCH (d)-[:DOCUMENTS]->(target) |
|
195
|
OPTIONAL MATCH (d)-[:DECIDED_BY]->(person:Person) |
|
196
|
OPTIONAL MATCH (d)-[:BELONGS_TO]->(domain:Domain) |
|
197
|
RETURN |
|
198
|
d.name AS name, d.description AS description, |
|
199
|
d.rationale AS rationale, d.alternatives AS alternatives, |
|
200
|
d.status AS status, d.date AS date, d.domain AS domain, |
|
201
|
collect(DISTINCT target.name) AS documents, |
|
202
|
collect(DISTINCT person.name) AS decided_by, |
|
203
|
collect(DISTINCT domain.name) AS domains |
|
204
|
""" |
|
205
|
|
|
206
|
# ── Knowledge: find owners (ASSIGNED_TO → Person) ──────────────────────────── |
|
207
|
|
|
208
|
FIND_OWNERS = """ |
|
209
|
MATCH (n)-[:ASSIGNED_TO]->(p:Person) |
|
210
|
WHERE n.name = $name AND ($file_path = '' OR n.file_path = $file_path) |
|
211
|
RETURN labels(n)[0] AS node_type, n.name AS node_name, |
|
212
|
p.name AS owner, p.email AS email, p.role AS role, p.team AS team |
|
213
|
""" |
|
214
|
|
|
215
|
# ── Incremental ingestion ───────────────────────────────────────────────────── |
|
216
|
|
|
217
|
FILE_HASH = """ |
|
218
|
MATCH (f:File {path: $path}) |
|
219
|
RETURN f.content_hash AS hash |
|
220
|
""" |
|
221
|
|
|
222
|
DELETE_FILE_SUBGRAPH = """ |
|
223
|
MATCH (f:File {path: $path})-[:CONTAINS]->(child) |
|
224
|
DETACH DELETE child |
|
225
|
""" |
|
226
|
|
|
227
|
# ── Stats ───────────────────────────────────────────────────────────────────── |
|
228
|
|
|
229
|
NODE_TYPE_COUNTS = """ |
|
230
|
MATCH (n) |
|
231
|
RETURN labels(n)[0] AS type, count(n) AS count |
|
232
|
ORDER BY count DESC |
|
233
|
""" |
|
234
|
|
|
235
|
EDGE_TYPE_COUNTS = """ |
|
236
|
MATCH ()-[r]->() |
|
237
|
RETURN type(r) AS type, count(r) AS count |
|
238
|
ORDER BY count DESC |
|
239
|
""" |
|
240
|
|