Skip to content

Instantly share code, notes, and snippets.

@62mkv
Last active May 24, 2022 13:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 62mkv/de2e98e261554f4f5d179edc0d1f3435 to your computer and use it in GitHub Desktop.
Save 62mkv/de2e98e261554f4f5d179edc0d1f3435 to your computer and use it in GitHub Desktop.
Cypher samples

Some jQAssistant Java-plugin graphs related Cypher queries

Add a label to "root" JARs (relevant for Spring Boot JARs)

Explanation: graph, created with jqassistant scan -f libs/, will created a lot of :Jar entries, but most of them will be "library" JARs, located under BOOT-INF/ folder. So the only JAR that represents the actual application code, will have fileName starting with something else (e.g. /application-name.jar)

MATCH (j:Jar)
WHERE left(j.fileName, 2) <> '/B'
SET j:AppJar
RETURN j

Add a label to application source classes (for Spring Boot JARs)

Explanation: application source code is placed under BOOT-INF/classes inside the application JAR. See previous example as well.

MATCH (j:AppJar)-[:CONTAINS]->(c:Java)
WHERE left(c.fileName, 18) = "/BOOT-INF/classes/"
    SET c:AppSource
RETURN c.fileName

Merge nodes for parent classes, scanned from source and from JARs

Explanation: for some reason, there're different nodes created for "parent" classes, scanned from application .class files; and for definitions of those classes, scanned from their corresponding JARs. So in order to be able to run meaningful queries, one would want to merge those nodes first:

MATCH (n1 {name: 'ParentClassName`}), (n2 {name: 'ParentClassName'})
WHERE id(n1)<id(n2)
WITH [n1,n2] as ns
CALL apoc.refactor.mergeNodes(ns) YIELD node
RETURN node

(see here)

Retrieving all application-defined classes, extending some library class either directly or via intermediate parent classes

MATCH (h:AppSource)-[:EXTENDS*]->(b {name: 'LibraryClassName'})
RETURN h

Counting lines and methods in certain classes

MATCH (h:AppSource)-[:EXTENDS*]->(b {name: 'LibraryClassName'}), (h)-[:DECLARES]->(m:Method)
WHERE m.synthetic is null
RETURN h.name, sum(m.effectiveLineCount), count(m)

Set application name based on directory name for bootJar

Explanation: 44 is length of a shared path to project root (say, X:\Projects\backend\)

MATCH (d:Directory)-[:CONTAINS]->(a:AppJar)
WITH a, substring(d.fileName, 44, length(d.fileName)-44) as trimmedFileName
SET a.appName = substring(trimmedFileName, 0, apoc.text.indexOf(trimmedFileName, '/'))
RETURN a

Assign a version to a Jar based on filename

MATCH (a:AppJar)-[:CONTAINS]->(b)
WHERE b.fileName STARTS WITH "/BOOT-INF/lib/event-"
WITH a, b, last(last(apoc.text.regexGroups(b.fileName, '/BOOT-INF/lib/event-([\\d\\.]+).jar'))) as version
SET b.version = version
RETURN a.appName, b.fileName, b.version
LIMIT 100

Importing data from CSV

Hint: on Windows machine, root of "import" directory seems to be at C:/, when embedded Neo4J server is used that is shipped with jQAssistant

LOAD CSV FROM 'file:///Users/Public/topics-sorted.csv' AS line
CREATE (:Topic {name: line[0]})
LOAD CSV FROM 'file:///Users/Public/misnamed-publishers.csv' as line
MATCH (t:Topic), (p:Publisher)<-[:DECLARES]-(c:Java)
where t.name = line[2] and c.appName = line[0] and p.name = line[1]
CREATE (p)-[:PUBLISHES_TO]->(t)
RETURN p, t;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment