Как найти пример экземпляра циклической зависимости в jQAssistant? - PullRequest
0 голосов
/ 04 мая 2018

Я обнаружил, что вывод ограничения 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)), но я не знаю другого способа отменить разрушительные эффекты раскрутки: структура окружающего списка удаляется, так что следы множественных циклических зависимостей сливаются друг с другом. Кроме того, результаты кажутся переставленными мне. Приведенный ниже запрос концептуально также очень близок к тому, чего я пытаюсь достичь, но не работает:

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 между двумя типами отсутствует):

<b>-[:DEPENDS_ON]-></b>(:Type)<-[:CONTAINS]-(:Package)-[:CONTAINS]->(:Type)<b>-[DEPENDS_ON]-></b>

Может быть, станет немного понятнее, используя следующую картинку:

Example Package Cycle

Ясно, что «a, b, c» - это цикл пакета, а «TestA, TestB1, TestB2, TestC» - это трассировка уровня типа для обоснования зависимости на уровне пакета.

1 Ответ

0 голосов
/ 06 мая 2018

Следующий запрос расширяет ограничение цикла пакета путем детализации на уровне типа:

MATCH
  (p1:Package)-[:DEPENDS_ON]->(p2:Package),
  path=shortestPath((p2)-[:DEPENDS_ON*]->(p1))
WHERE
  p1 <> p2
WITH
  p1, p2
MATCH
  (p1)-[:CONTAINS]->(t1:Type),
  (p2)-[:CONTAINS]->(t2:Type),
  (p1)-[:CONTAINS]->(t3:Type),
  (t1)-[:DEPENDS_ON]->(t2),
  path=shortestPath((t2)-[:DEPENDS_ON*]->(t3))
RETURN
  p1.fqn, t1.fqn, EXTRACT(t IN nodes(path) | t.fqn) AS Cycle

Я не уверен, насколько хорошо запрос будет работать в больших проектах, нам нужно попробовать его.

Редактировать 1: обновлен запрос для соответствия любому типу t3, который находится в том же пакете, что и t1.

Редактировать 2: Ответ неправильный, см. Обсуждение ниже.

...