Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions src/main/java/io/github/randomcodespace/iq/graph/GraphStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
* Creates an index on CodeNode.id for fast MATCH during edge creation.
* Logs progress every 10K items for visibility on large graphs.
*/
public void bulkSave(List<CodeNode> nodes) {

Check warning on line 71 in src/main/java/io/github/randomcodespace/iq/graph/GraphStore.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

A "Brain Method" was detected. Refactor it to reduce at least one of the following metrics: LOC from 87 to 64, Complexity from 19 to 14, Nesting Level from 3 to 2, Number of Variables from 29 to 6.

See more on https://sonarcloud.io/project/issues?id=RandomCodeSpace_code-iq&issues=AZ1UJHMbhf7x-hm_YDzO&open=AZ1UJHMbhf7x-hm_YDzO&pullRequest=25
if (nodes.isEmpty()) return;
long start = System.currentTimeMillis();

Expand Down Expand Up @@ -335,31 +335,6 @@
Map.of("nodeId", nodeId));
}

/**
* Batch-find all ENDPOINT/WEBSOCKET_ENDPOINT neighbors for a list of node IDs in one query.
* Returns a map of sourceNodeId -> list of endpoint neighbor nodes.
*/
public Map<String, List<CodeNode>> findEndpointNeighborsBatch(List<String> nodeIds) {
Map<String, List<CodeNode>> result = new java.util.LinkedHashMap<>();
if (nodeIds.isEmpty()) return result;
try (Transaction tx = graphDb.beginTx()) {
var queryResult = tx.execute(
"MATCH (n:CodeNode)-[]-(m:CodeNode) "
+ "WHERE n.id IN $nodeIds AND m.kind IN ['ENDPOINT', 'WEBSOCKET_ENDPOINT'] "
+ "RETURN n.id AS sourceId, m",
Map.of("nodeIds", nodeIds));
while (queryResult.hasNext()) {
var row = queryResult.next();
String sourceId = (String) row.get("sourceId");
Object val = row.get("m");
if (val instanceof org.neo4j.graphdb.Node neo4jNode) {
result.computeIfAbsent(sourceId, k -> new ArrayList<>()).add(nodeFromNeo4j(neo4jNode));
}
}
}
return result;
}

public long count() {
try (Transaction tx = graphDb.beginTx()) {
var result = tx.execute("MATCH (n:CodeNode) RETURN count(n) AS cnt");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,30 +376,4 @@ void handlesMessageQueueNodeKind() {
assertEquals(1, result.edges().size());
}

@Test
void determinismTest() {
var topic = new CodeNode("topic:payments", NodeKind.TOPIC, "payments");
var prod1 = new CodeNode("svc:P1", NodeKind.CLASS, "P1");
var prod2 = new CodeNode("svc:P2", NodeKind.CLASS, "P2");
var cons = new CodeNode("svc:C1", NodeKind.CLASS, "C1");

var e1 = new CodeEdge();
e1.setId("e1"); e1.setKind(EdgeKind.PUBLISHES); e1.setSourceId("svc:P1"); e1.setTarget(topic);
var e2 = new CodeEdge();
e2.setId("e2"); e2.setKind(EdgeKind.SENDS_TO); e2.setSourceId("svc:P2"); e2.setTarget(topic);
var e3 = new CodeEdge();
e3.setId("e3"); e3.setKind(EdgeKind.LISTENS); e3.setSourceId("svc:C1"); e3.setTarget(topic);

List<CodeNode> nodeList = new ArrayList<>(List.of(topic, prod1, prod2, cons));
List<CodeEdge> edgeList = new ArrayList<>(List.of(e1, e2, e3));

LinkResult result1 = linker.link(nodeList, edgeList);
LinkResult result2 = linker.link(nodeList, edgeList);

assertEquals(result1.edges().size(), result2.edges().size());
for (int i = 0; i < result1.edges().size(); i++) {
assertEquals(result1.edges().get(i).getId(), result2.edges().get(i).getId());
assertEquals(result1.edges().get(i).getSourceId(), result2.edges().get(i).getSourceId());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,8 @@ void findRelatedEndpointsShouldUsesBatchQueryInsteadOfNPlusOne() {
void findRelatedEndpointsShouldIncludeDirectEndpointMatches() {
var endpointNode = makeNode("ep:getUsers", NodeKind.ENDPOINT, "getUsers");
when(graphStore.search("getUsers", 50)).thenReturn(List.of(endpointNode));
when(graphStore.findEndpointNeighborsBatch(List.of("ep:getUsers"))).thenReturn(Map.of());
// Endpoint nodes are partitioned directly into the result list — nonEndpointIds is empty
when(graphStore.findEndpointNeighborsBatch(List.of())).thenReturn(Map.of());

Map<String, Object> result = service.findRelatedEndpoints("getUsers");

Expand All @@ -586,14 +587,13 @@ void findRelatedEndpointsShouldIncludeDirectEndpointMatches() {
@Test
void findRelatedEndpointsShouldDeduplicateEndpoints() {
var endpointNode = makeNode("ep:getUsers", NodeKind.ENDPOINT, "getUsers");
// Same endpoint appears as both a direct match and a neighbor
// Endpoint node is a direct match — nonEndpointIds is empty, batch returns nothing
when(graphStore.search("ep", 50)).thenReturn(List.of(endpointNode));
when(graphStore.findEndpointNeighborsBatch(List.of("ep:getUsers")))
.thenReturn(Map.of("ep:getUsers", List.of(endpointNode)));
when(graphStore.findEndpointNeighborsBatch(List.of())).thenReturn(Map.of());

Map<String, Object> result = service.findRelatedEndpoints("ep");

// Should only appear once
// Should appear exactly once (direct match)
assertEquals(1, result.get("count"));
}

Expand Down
Loading