我发现 dependency:packageCycles
jQAssistant 附带的约束输出很难解释。具体来说,我热衷于找到构成循环依赖的类的示例实例。
鉴于我找到了一个包循环,对于每一对附加包,我需要找到两个连接它们的类。
这是我第一次尝试 Cypher 查询,但仍然缺少一些相关部分:
MATCH nodes = (p1:Package)-[:DEPENDS_ON]->(p2: Package)-[:DEPENDS_ON*]->(p1)
WHERE p1 <> p2
WITH extract(x IN relationships(nodes) |
(:Type)<--(:Package)-[x]->(:Package)-->(:Type)) AS cs
RETURN cs
具体来说,为了真正连接这两个包,这两种类型应该相互关联,DEPENDS_ON
如下所示:
(:Type)<--(:Package)-[x]->(:Package)-->(:Type)
| ^
| DEPENDS_ON |
+--------------------------------------+
对于上述模式,我必须返回两种类型(例如,而不是包)。优选地,单个循环依赖的输出由一个合格的类名列表组成(否则多个不能区分多个循环依赖的类链)。
对于这个特定的目的,我发现 Cypher 非常有限,支持在路径遍历期间识别和收集新的图形模式似乎不是最容易做的事情。此外,尝试为(:Type)
节点命名会导致语法错误。
我也搞砸了很多UNWIND
,但无济于事。MATCH
它可以让你在每个元素的基础上引入新的子句(比如 的元素relationships(nodes)
),但我不知道有另一种方法可以消除 unwind 的破坏性影响:移除周围的列表结构,这样多个循环依赖的痕迹相互融合。此外,结果对我来说似乎已经改变了。话虽如此,下面的查询在概念上也非常接近我想要实现但不起作用的目标:
MATCH nodes = (p1:Package)-[:DEPENDS_ON]->(p2: Package)-[:DEPENDS_ON*]->(p1)
WHERE p1 <> p2
WITH relationships(nodes) as rel
UNWIND rel AS x
MATCH (t0:Type)<-[:CONTAINS]-(:Package)-[x]->(:Package)-[:CONTAINS]->(t1:Type),
(t0)-[:DEPENDS_ON]->(t1)
RETURN t0.fqn, t1.fqn
我很欣赏 jQAssistant 中似乎有一些脚本支持。但是,这确实是我最后的手段,因为它肯定比 Cypher 查询更难维护。
换个说法:给定一条路径,我正在寻找一种方法来识别每个元素的子模式,从匹配中投影一个节点,并收集结果。您对如何使用 Cypher 实现这一目标有任何想法吗?
编辑#1:在一个包中,还必须考虑到类型的入站边缘的目标类DEPENDS_ON
可能与传出边缘的源类不同。换句话说,结果
- 同一包的两个类可能是跟踪的一部分
- 如果要将循环依赖跟踪表示为路径,则必须考虑导航到同一包中的类的弯路。例如(粗体标记包进入/退出的边缘;
DEPENDS_ON
两种类型之间没有类型的边缘):
-[:DEPENDS_ON]->(:Type)<-[:CONTAINS]-(:Package)-[:CONTAINS]->(:Type)-[DEPENDS_ON]->
使用下图可能会更清楚一些:
显然,“a、b、c”是一个包循环,“TestA、TestB1、TestB2、TestC”是用于证明包级依赖关系的类型级跟踪。