Skip to content

Commit a655a94

Browse files
aksOpsclaude
andcommitted
fix: file tree LIMIT overflow + edge kind breakdown from Neo4j
- getFilePathsWithCounts: Integer.MAX_VALUE + 1 overflowed to negative LIMIT in Cypher. Now skips LIMIT clause for maxFiles > 1M. - computeGraphStats: added edges_by_kind Cypher aggregation so the /api/stats endpoint includes edge kind breakdown (calls, imports, contains, depends_on, etc.) — Dashboard Edges card now works. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d531e56 commit a655a94

1 file changed

Lines changed: 26 additions & 6 deletions

File tree

src/main/java/io/github/randomcodespace/iq/graph/GraphStore.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.github.randomcodespace.iq.model.EdgeKind;
77
import io.github.randomcodespace.iq.model.NodeKind;
88
import org.neo4j.graphdb.GraphDatabaseService;
9+
import org.neo4j.graphdb.Result;
910
import org.neo4j.graphdb.Transaction;
1011
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
1112
import org.springframework.stereotype.Service;
@@ -658,12 +659,18 @@ public record FilePathResult(List<Map<String, Object>> rows, boolean truncated)
658659
public FilePathResult getFilePathsWithCounts(int maxFiles) {
659660
List<Map<String, Object>> rows = new ArrayList<>();
660661
try (Transaction tx = graphDb.beginTx()) {
661-
var result = tx.execute(
662-
"MATCH (n:CodeNode) WHERE n.filePath IS NOT NULL "
663-
+ "RETURN n.filePath AS filePath, count(n) AS nodeCount "
664-
+ "ORDER BY n.filePath "
665-
+ "LIMIT $limit",
666-
Map.of(PROP_LIMIT, (long) (maxFiles + 1)));
662+
// When maxFiles is very large (e.g., Integer.MAX_VALUE for unlimited treemap),
663+
// skip the LIMIT clause entirely to avoid integer overflow
664+
String query = "MATCH (n:CodeNode) WHERE n.filePath IS NOT NULL "
665+
+ "RETURN n.filePath AS filePath, count(n) AS nodeCount "
666+
+ "ORDER BY n.filePath";
667+
Result result;
668+
if (maxFiles < 1_000_000) {
669+
result = tx.execute(query + " LIMIT $limit",
670+
Map.of(PROP_LIMIT, (long) (maxFiles + 1)));
671+
} else {
672+
result = tx.execute(query);
673+
}
667674
while (result.hasNext()) {
668675
var row = result.next();
669676
Map<String, Object> m = new LinkedHashMap<>();
@@ -866,6 +873,19 @@ private Map<String, Object> computeGraphStats() {
866873
"MATCH (n:CodeNode) WHERE n.filePath IS NOT NULL AND n.filePath <> '' "
867874
+ "RETURN count(DISTINCT n.filePath) AS cnt");
868875
graph.put("files", r3.hasNext() ? ((Number) r3.next().get(PROP_CNT)).longValue() : 0L);
876+
877+
// Edge kind breakdown
878+
var r4 = tx.execute(
879+
"MATCH ()-[r:RELATES_TO]->() "
880+
+ "RETURN r.kind AS kind, count(r) AS cnt ORDER BY cnt DESC");
881+
Map<String, Long> edgesByKind = new LinkedHashMap<>();
882+
while (r4.hasNext()) {
883+
var row = r4.next();
884+
String kind = (String) row.get(PROP_KIND);
885+
long cnt = ((Number) row.get(PROP_CNT)).longValue();
886+
if (kind != null) edgesByKind.put(kind, cnt);
887+
}
888+
graph.put("edges_by_kind", edgesByKind);
869889
}
870890
return graph;
871891
}

0 commit comments

Comments
 (0)