infrahub-server 1.2.0rc0__py3-none-any.whl → 1.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (365) hide show
  1. infrahub/api/dependencies.py +6 -6
  2. infrahub/api/diff/validation_models.py +7 -7
  3. infrahub/api/schema.py +1 -1
  4. infrahub/artifacts/models.py +5 -3
  5. infrahub/artifacts/tasks.py +3 -5
  6. infrahub/cli/__init__.py +13 -9
  7. infrahub/cli/constants.py +3 -0
  8. infrahub/cli/db.py +165 -183
  9. infrahub/cli/upgrade.py +146 -0
  10. infrahub/computed_attribute/gather.py +185 -0
  11. infrahub/computed_attribute/models.py +240 -12
  12. infrahub/computed_attribute/tasks.py +72 -432
  13. infrahub/computed_attribute/triggers.py +13 -47
  14. infrahub/config.py +43 -32
  15. infrahub/context.py +14 -0
  16. infrahub/core/account.py +4 -4
  17. infrahub/core/attribute.py +58 -58
  18. infrahub/core/branch/tasks.py +74 -22
  19. infrahub/core/changelog/diff.py +95 -36
  20. infrahub/core/changelog/models.py +217 -43
  21. infrahub/core/constants/__init__.py +28 -0
  22. infrahub/core/constants/infrahubkind.py +2 -0
  23. infrahub/core/constants/schema.py +2 -0
  24. infrahub/core/constraint/node/runner.py +9 -8
  25. infrahub/core/diff/branch_differ.py +10 -10
  26. infrahub/core/diff/enricher/cardinality_one.py +5 -0
  27. infrahub/core/diff/enricher/hierarchy.py +17 -4
  28. infrahub/core/diff/enricher/labels.py +5 -0
  29. infrahub/core/diff/enricher/path_identifier.py +4 -0
  30. infrahub/core/diff/ipam_diff_parser.py +4 -5
  31. infrahub/core/diff/model/diff.py +27 -27
  32. infrahub/core/diff/model/path.py +32 -9
  33. infrahub/core/diff/parent_node_adder.py +78 -0
  34. infrahub/core/diff/payload_builder.py +13 -2
  35. infrahub/core/diff/query/filters.py +2 -2
  36. infrahub/core/diff/query/merge.py +20 -17
  37. infrahub/core/diff/query/save.py +188 -182
  38. infrahub/core/diff/query/summary_counts_enricher.py +51 -4
  39. infrahub/core/diff/query_parser.py +4 -4
  40. infrahub/core/diff/repository/deserializer.py +8 -3
  41. infrahub/core/diff/repository/repository.py +156 -38
  42. infrahub/core/diff/tasks.py +4 -4
  43. infrahub/core/graph/__init__.py +1 -1
  44. infrahub/core/graph/index.py +3 -0
  45. infrahub/core/initialization.py +1 -10
  46. infrahub/core/ipam/constants.py +3 -4
  47. infrahub/core/ipam/reconciler.py +12 -12
  48. infrahub/core/ipam/utilization.py +10 -13
  49. infrahub/core/manager.py +36 -36
  50. infrahub/core/merge.py +7 -7
  51. infrahub/core/migrations/__init__.py +2 -3
  52. infrahub/core/migrations/graph/__init__.py +12 -3
  53. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
  54. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
  55. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +256 -0
  56. infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
  57. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
  58. infrahub/core/migrations/graph/m022_add_generate_template_attr.py +48 -0
  59. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
  60. infrahub/core/migrations/query/attribute_add.py +2 -2
  61. infrahub/core/migrations/query/node_duplicate.py +43 -26
  62. infrahub/core/migrations/query/schema_attribute_update.py +2 -2
  63. infrahub/core/migrations/schema/models.py +19 -4
  64. infrahub/core/migrations/schema/node_remove.py +26 -12
  65. infrahub/core/migrations/schema/tasks.py +2 -2
  66. infrahub/core/migrations/shared.py +16 -16
  67. infrahub/core/models.py +15 -6
  68. infrahub/core/node/__init__.py +43 -39
  69. infrahub/core/node/base.py +2 -4
  70. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  71. infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
  72. infrahub/core/node/constraints/interface.py +1 -2
  73. infrahub/core/node/delete_validator.py +3 -5
  74. infrahub/core/node/ipam.py +4 -4
  75. infrahub/core/node/permissions.py +7 -7
  76. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  77. infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
  78. infrahub/core/node/resource_manager/number_pool.py +3 -3
  79. infrahub/core/path.py +12 -12
  80. infrahub/core/property.py +11 -11
  81. infrahub/core/protocols.py +7 -0
  82. infrahub/core/protocols_base.py +21 -21
  83. infrahub/core/query/__init__.py +33 -33
  84. infrahub/core/query/attribute.py +6 -4
  85. infrahub/core/query/diff.py +3 -3
  86. infrahub/core/query/node.py +98 -37
  87. infrahub/core/query/relationship.py +228 -40
  88. infrahub/core/query/resource_manager.py +2 -0
  89. infrahub/core/query/standard_node.py +3 -3
  90. infrahub/core/query/subquery.py +9 -9
  91. infrahub/core/registry.py +13 -15
  92. infrahub/core/relationship/constraints/count.py +3 -4
  93. infrahub/core/relationship/constraints/peer_kind.py +3 -4
  94. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  95. infrahub/core/relationship/model.py +51 -59
  96. infrahub/core/schema/attribute_schema.py +16 -8
  97. infrahub/core/schema/basenode_schema.py +105 -44
  98. infrahub/core/schema/computed_attribute.py +3 -3
  99. infrahub/core/schema/definitions/core/__init__.py +147 -0
  100. infrahub/core/schema/definitions/core/account.py +171 -0
  101. infrahub/core/schema/definitions/core/artifact.py +136 -0
  102. infrahub/core/schema/definitions/core/builtin.py +24 -0
  103. infrahub/core/schema/definitions/core/check.py +68 -0
  104. infrahub/core/schema/definitions/core/core.py +17 -0
  105. infrahub/core/schema/definitions/core/generator.py +100 -0
  106. infrahub/core/schema/definitions/core/graphql_query.py +79 -0
  107. infrahub/core/schema/definitions/core/group.py +108 -0
  108. infrahub/core/schema/definitions/core/ipam.py +193 -0
  109. infrahub/core/schema/definitions/core/lineage.py +19 -0
  110. infrahub/core/schema/definitions/core/menu.py +48 -0
  111. infrahub/core/schema/definitions/core/permission.py +163 -0
  112. infrahub/core/schema/definitions/core/profile.py +18 -0
  113. infrahub/core/schema/definitions/core/propose_change.py +97 -0
  114. infrahub/core/schema/definitions/core/propose_change_comment.py +193 -0
  115. infrahub/core/schema/definitions/core/propose_change_validator.py +328 -0
  116. infrahub/core/schema/definitions/core/repository.py +286 -0
  117. infrahub/core/schema/definitions/core/resource_pool.py +170 -0
  118. infrahub/core/schema/definitions/core/template.py +27 -0
  119. infrahub/core/schema/definitions/core/transform.py +96 -0
  120. infrahub/core/schema/definitions/core/webhook.py +134 -0
  121. infrahub/core/schema/definitions/internal.py +16 -16
  122. infrahub/core/schema/dropdown.py +3 -4
  123. infrahub/core/schema/generated/attribute_schema.py +15 -18
  124. infrahub/core/schema/generated/base_node_schema.py +12 -14
  125. infrahub/core/schema/generated/node_schema.py +3 -5
  126. infrahub/core/schema/generated/relationship_schema.py +9 -11
  127. infrahub/core/schema/generic_schema.py +2 -2
  128. infrahub/core/schema/manager.py +20 -9
  129. infrahub/core/schema/node_schema.py +4 -2
  130. infrahub/core/schema/relationship_schema.py +14 -6
  131. infrahub/core/schema/schema_branch.py +292 -144
  132. infrahub/core/schema/schema_branch_computed.py +41 -4
  133. infrahub/core/task/task.py +3 -3
  134. infrahub/core/task/user_task.py +15 -15
  135. infrahub/core/timestamp.py +3 -3
  136. infrahub/core/utils.py +20 -18
  137. infrahub/core/validators/__init__.py +1 -3
  138. infrahub/core/validators/aggregated_checker.py +2 -2
  139. infrahub/core/validators/attribute/choices.py +2 -2
  140. infrahub/core/validators/attribute/enum.py +2 -2
  141. infrahub/core/validators/attribute/kind.py +2 -2
  142. infrahub/core/validators/attribute/length.py +2 -2
  143. infrahub/core/validators/attribute/optional.py +2 -2
  144. infrahub/core/validators/attribute/regex.py +2 -2
  145. infrahub/core/validators/attribute/unique.py +2 -2
  146. infrahub/core/validators/checks_runner.py +25 -2
  147. infrahub/core/validators/determiner.py +1 -3
  148. infrahub/core/validators/interface.py +6 -2
  149. infrahub/core/validators/model.py +22 -3
  150. infrahub/core/validators/models/validate_migration.py +17 -4
  151. infrahub/core/validators/node/attribute.py +2 -2
  152. infrahub/core/validators/node/generate_profile.py +2 -2
  153. infrahub/core/validators/node/hierarchy.py +3 -5
  154. infrahub/core/validators/node/inherit_from.py +27 -5
  155. infrahub/core/validators/node/relationship.py +2 -2
  156. infrahub/core/validators/relationship/count.py +4 -4
  157. infrahub/core/validators/relationship/optional.py +2 -2
  158. infrahub/core/validators/relationship/peer.py +2 -2
  159. infrahub/core/validators/shared.py +2 -2
  160. infrahub/core/validators/tasks.py +8 -0
  161. infrahub/core/validators/uniqueness/checker.py +22 -21
  162. infrahub/core/validators/uniqueness/index.py +2 -2
  163. infrahub/core/validators/uniqueness/model.py +11 -11
  164. infrahub/database/__init__.py +27 -22
  165. infrahub/database/metrics.py +7 -1
  166. infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
  167. infrahub/dependencies/builder/diff/deserializer.py +3 -1
  168. infrahub/dependencies/builder/diff/enricher/hierarchy.py +3 -1
  169. infrahub/dependencies/builder/diff/parent_node_adder.py +8 -0
  170. infrahub/dependencies/component/registry.py +2 -2
  171. infrahub/events/__init__.py +25 -2
  172. infrahub/events/artifact_action.py +64 -0
  173. infrahub/events/branch_action.py +33 -22
  174. infrahub/events/generator.py +71 -0
  175. infrahub/events/group_action.py +51 -21
  176. infrahub/events/models.py +18 -19
  177. infrahub/events/node_action.py +88 -37
  178. infrahub/events/repository_action.py +5 -18
  179. infrahub/events/schema_action.py +4 -9
  180. infrahub/events/utils.py +16 -0
  181. infrahub/events/validator_action.py +55 -0
  182. infrahub/exceptions.py +62 -26
  183. infrahub/generators/models.py +2 -3
  184. infrahub/generators/tasks.py +24 -4
  185. infrahub/git/base.py +87 -36
  186. infrahub/git/integrator.py +48 -48
  187. infrahub/git/models.py +101 -9
  188. infrahub/git/repository.py +3 -3
  189. infrahub/git/tasks.py +408 -6
  190. infrahub/git/utils.py +48 -0
  191. infrahub/git/worktree.py +1 -2
  192. infrahub/git_credential/askpass.py +1 -2
  193. infrahub/graphql/analyzer.py +12 -0
  194. infrahub/graphql/app.py +13 -15
  195. infrahub/graphql/context.py +39 -0
  196. infrahub/graphql/initialization.py +3 -0
  197. infrahub/graphql/loaders/node.py +2 -12
  198. infrahub/graphql/loaders/peers.py +77 -0
  199. infrahub/graphql/loaders/shared.py +13 -0
  200. infrahub/graphql/manager.py +17 -19
  201. infrahub/graphql/mutations/artifact_definition.py +5 -5
  202. infrahub/graphql/mutations/branch.py +26 -1
  203. infrahub/graphql/mutations/computed_attribute.py +9 -5
  204. infrahub/graphql/mutations/diff.py +23 -11
  205. infrahub/graphql/mutations/diff_conflict.py +5 -0
  206. infrahub/graphql/mutations/generator.py +83 -0
  207. infrahub/graphql/mutations/graphql_query.py +5 -5
  208. infrahub/graphql/mutations/ipam.py +54 -74
  209. infrahub/graphql/mutations/main.py +195 -132
  210. infrahub/graphql/mutations/menu.py +7 -7
  211. infrahub/graphql/mutations/models.py +2 -4
  212. infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
  213. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  214. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  215. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  216. infrahub/graphql/mutations/proposed_change.py +7 -7
  217. infrahub/graphql/mutations/relationship.py +93 -19
  218. infrahub/graphql/mutations/repository.py +8 -8
  219. infrahub/graphql/mutations/resource_manager.py +3 -3
  220. infrahub/graphql/mutations/schema.py +19 -4
  221. infrahub/graphql/mutations/webhook.py +137 -0
  222. infrahub/graphql/parser.py +4 -4
  223. infrahub/graphql/permissions.py +1 -10
  224. infrahub/graphql/queries/diff/tree.py +19 -14
  225. infrahub/graphql/queries/event.py +5 -2
  226. infrahub/graphql/queries/ipam.py +2 -2
  227. infrahub/graphql/queries/relationship.py +2 -2
  228. infrahub/graphql/queries/search.py +2 -2
  229. infrahub/graphql/resolvers/many_relationship.py +264 -0
  230. infrahub/graphql/resolvers/resolver.py +13 -110
  231. infrahub/graphql/schema.py +2 -0
  232. infrahub/graphql/subscription/graphql_query.py +2 -0
  233. infrahub/graphql/types/context.py +12 -0
  234. infrahub/graphql/types/event.py +84 -17
  235. infrahub/graphql/types/node.py +2 -2
  236. infrahub/graphql/utils.py +2 -2
  237. infrahub/groups/ancestors.py +29 -0
  238. infrahub/groups/parsers.py +107 -0
  239. infrahub/lock.py +20 -20
  240. infrahub/menu/constants.py +0 -1
  241. infrahub/menu/generator.py +9 -21
  242. infrahub/menu/menu.py +17 -38
  243. infrahub/menu/models.py +117 -16
  244. infrahub/menu/repository.py +111 -0
  245. infrahub/menu/utils.py +5 -8
  246. infrahub/message_bus/__init__.py +11 -13
  247. infrahub/message_bus/messages/__init__.py +1 -21
  248. infrahub/message_bus/messages/check_generator_run.py +3 -3
  249. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  250. infrahub/message_bus/messages/proposed_change/request_proposedchange_refreshartifacts.py +6 -0
  251. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  252. infrahub/message_bus/messages/send_echo_request.py +1 -1
  253. infrahub/message_bus/operations/__init__.py +1 -10
  254. infrahub/message_bus/operations/check/__init__.py +2 -2
  255. infrahub/message_bus/operations/check/generator.py +1 -0
  256. infrahub/message_bus/operations/event/__init__.py +2 -2
  257. infrahub/message_bus/operations/event/worker.py +0 -3
  258. infrahub/message_bus/operations/finalize/validator.py +51 -1
  259. infrahub/message_bus/operations/requests/__init__.py +0 -2
  260. infrahub/message_bus/operations/requests/generator_definition.py +21 -23
  261. infrahub/message_bus/operations/requests/proposed_change.py +14 -10
  262. infrahub/permissions/globals.py +15 -0
  263. infrahub/pools/number.py +2 -4
  264. infrahub/proposed_change/models.py +3 -0
  265. infrahub/proposed_change/tasks.py +58 -45
  266. infrahub/pytest_plugin.py +13 -10
  267. infrahub/server.py +2 -3
  268. infrahub/services/__init__.py +2 -2
  269. infrahub/services/adapters/cache/__init__.py +4 -6
  270. infrahub/services/adapters/cache/nats.py +4 -5
  271. infrahub/services/adapters/cache/redis.py +3 -7
  272. infrahub/services/adapters/event/__init__.py +1 -1
  273. infrahub/services/adapters/message_bus/__init__.py +3 -3
  274. infrahub/services/adapters/message_bus/local.py +2 -2
  275. infrahub/services/adapters/message_bus/nats.py +4 -4
  276. infrahub/services/adapters/message_bus/rabbitmq.py +4 -4
  277. infrahub/services/adapters/workflow/local.py +2 -2
  278. infrahub/services/component.py +5 -5
  279. infrahub/services/protocols.py +7 -7
  280. infrahub/services/scheduler.py +1 -3
  281. infrahub/task_manager/event.py +102 -9
  282. infrahub/task_manager/models.py +27 -7
  283. infrahub/tasks/artifact.py +7 -6
  284. infrahub/telemetry/__init__.py +0 -0
  285. infrahub/telemetry/constants.py +9 -0
  286. infrahub/telemetry/database.py +86 -0
  287. infrahub/telemetry/models.py +65 -0
  288. infrahub/telemetry/task_manager.py +77 -0
  289. infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
  290. infrahub/telemetry/utils.py +11 -0
  291. infrahub/trace.py +4 -4
  292. infrahub/transformations/tasks.py +2 -2
  293. infrahub/trigger/catalogue.py +4 -6
  294. infrahub/trigger/constants.py +0 -8
  295. infrahub/trigger/models.py +54 -5
  296. infrahub/trigger/setup.py +90 -0
  297. infrahub/trigger/tasks.py +35 -83
  298. infrahub/utils.py +11 -1
  299. infrahub/validators/__init__.py +0 -0
  300. infrahub/validators/events.py +42 -0
  301. infrahub/validators/tasks.py +41 -0
  302. infrahub/webhook/gather.py +17 -0
  303. infrahub/webhook/models.py +176 -44
  304. infrahub/webhook/tasks.py +154 -155
  305. infrahub/webhook/triggers.py +31 -7
  306. infrahub/workers/infrahub_async.py +2 -2
  307. infrahub/workers/utils.py +2 -2
  308. infrahub/workflows/catalogue.py +86 -35
  309. infrahub/workflows/initialization.py +8 -2
  310. infrahub/workflows/models.py +27 -1
  311. infrahub/workflows/utils.py +15 -6
  312. infrahub_sdk/client.py +35 -8
  313. infrahub_sdk/config.py +3 -0
  314. infrahub_sdk/context.py +13 -0
  315. infrahub_sdk/ctl/branch.py +3 -2
  316. infrahub_sdk/ctl/cli_commands.py +5 -1
  317. infrahub_sdk/ctl/utils.py +0 -16
  318. infrahub_sdk/exceptions.py +12 -0
  319. infrahub_sdk/generator.py +4 -1
  320. infrahub_sdk/graphql.py +45 -13
  321. infrahub_sdk/node.py +73 -22
  322. infrahub_sdk/protocols.py +21 -8
  323. infrahub_sdk/protocols_base.py +32 -11
  324. infrahub_sdk/query_groups.py +6 -35
  325. infrahub_sdk/schema/__init__.py +55 -26
  326. infrahub_sdk/schema/main.py +8 -0
  327. infrahub_sdk/task/__init__.py +11 -0
  328. infrahub_sdk/task/constants.py +3 -0
  329. infrahub_sdk/task/exceptions.py +25 -0
  330. infrahub_sdk/task/manager.py +551 -0
  331. infrahub_sdk/task/models.py +74 -0
  332. infrahub_sdk/testing/schemas/animal.py +9 -0
  333. infrahub_sdk/timestamp.py +142 -33
  334. infrahub_sdk/utils.py +29 -1
  335. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/METADATA +8 -6
  336. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/RECORD +349 -293
  337. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/entry_points.txt +1 -0
  338. infrahub_testcontainers/constants.py +2 -0
  339. infrahub_testcontainers/container.py +157 -12
  340. infrahub_testcontainers/docker-compose.test.yml +31 -6
  341. infrahub_testcontainers/helpers.py +18 -73
  342. infrahub_testcontainers/host.py +41 -0
  343. infrahub_testcontainers/measurements.py +93 -0
  344. infrahub_testcontainers/models.py +38 -0
  345. infrahub_testcontainers/performance_test.py +166 -0
  346. infrahub_testcontainers/plugin.py +136 -0
  347. infrahub_testcontainers/prometheus.yml +30 -0
  348. infrahub/core/schema/definitions/core.py +0 -2286
  349. infrahub/message_bus/messages/check_repository_checkdefinition.py +0 -20
  350. infrahub/message_bus/messages/check_repository_mergeconflicts.py +0 -16
  351. infrahub/message_bus/messages/check_repository_usercheck.py +0 -26
  352. infrahub/message_bus/messages/event_branch_create.py +0 -11
  353. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  354. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  355. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  356. infrahub/message_bus/messages/event_schema_update.py +0 -9
  357. infrahub/message_bus/messages/request_repository_checks.py +0 -12
  358. infrahub/message_bus/messages/request_repository_userchecks.py +0 -18
  359. infrahub/message_bus/operations/check/repository.py +0 -293
  360. infrahub/message_bus/operations/event/node.py +0 -20
  361. infrahub/message_bus/operations/event/schema.py +0 -17
  362. infrahub/message_bus/operations/requests/repository.py +0 -133
  363. infrahub/webhook/constants.py +0 -1
  364. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/LICENSE.txt +0 -0
  365. {infrahub_server-1.2.0rc0.dist-info → infrahub_server-1.2.2.dist-info}/WHEEL +0 -0
@@ -36,6 +36,7 @@ class DiffMergeQuery(Query):
36
36
  "target_branch": self.target_branch.name,
37
37
  "source_branch": self.source_branch_name,
38
38
  }
39
+ # ruff: noqa: E501
39
40
  query = """
40
41
  UNWIND $node_diff_dicts AS node_diff_map
41
42
  CALL {
@@ -242,9 +243,11 @@ CALL {
242
243
  CASE
243
244
  WHEN startNode(source_r_rel_2).uuid = r.uuid THEN "r"
244
245
  ELSE "l"
245
- END AS r2_dir
246
+ END AS r2_dir,
247
+ source_r_rel_1.hierarchy AS r1_hierarchy,
248
+ source_r_rel_2.hierarchy AS r2_hierarchy
246
249
  }
247
- WITH n, r, r1_dir, r2_dir, rel_name, rel_peer_id, related_rel_status
250
+ WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status
248
251
  CALL {
249
252
  WITH n, rel_name, rel_peer_id, related_rel_status
250
253
  OPTIONAL MATCH (n)
@@ -258,12 +261,12 @@ CALL {
258
261
  SET target_r_rel_1.to = $at
259
262
  SET target_r_rel_2.to = $at
260
263
  }
261
- WITH n, r, r1_dir, r2_dir, rel_name, rel_peer_id, related_rel_status
264
+ WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status
262
265
  // ------------------------------
263
266
  // conditionally create new IS_RELATED relationships on target_branch, if necessary
264
267
  // ------------------------------
265
268
  CALL {
266
- WITH n, r, r1_dir, r2_dir, rel_name, rel_peer_id, related_rel_status
269
+ WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, rel_name, rel_peer_id, related_rel_status
267
270
  MATCH (p:Node {uuid: rel_peer_id})
268
271
  OPTIONAL MATCH (n)
269
272
  -[r_rel_1:IS_RELATED {branch: $target_branch, status: related_rel_status}]
@@ -274,42 +277,42 @@ CALL {
274
277
  AND (r_rel_1.to >= $at OR r_rel_1.to IS NULL)
275
278
  AND r_rel_2.from <= $at
276
279
  AND (r_rel_2.to >= $at OR r_rel_2.to IS NULL)
277
- WITH n, r, r1_dir, r2_dir, p, related_rel_status, r_rel_1, r_rel_2
280
+ WITH n, r, r1_dir, r2_dir, r1_hierarchy, r2_hierarchy, p, related_rel_status, r_rel_1, r_rel_2
278
281
  WHERE r_rel_1 IS NULL
279
282
  AND r_rel_2 IS NULL
280
283
  // ------------------------------
281
284
  // create IS_RELATED relationships with directions maintained from source
282
285
  // ------------------------------
283
286
  CALL {
284
- WITH n, r, r1_dir, related_rel_status
285
- WITH n, r, r1_dir, related_rel_status
287
+ WITH n, r, r1_dir, r1_hierarchy, related_rel_status
288
+ WITH n, r, r1_dir, r1_hierarchy, related_rel_status
286
289
  WHERE r1_dir = "r"
287
290
  CREATE (n)
288
- -[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status}]
291
+ -[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r1_hierarchy}]
289
292
  ->(r)
290
293
  }
291
294
  CALL {
292
- WITH n, r, r1_dir, related_rel_status
293
- WITH n, r, r1_dir, related_rel_status
295
+ WITH n, r, r1_dir, r1_hierarchy, related_rel_status
296
+ WITH n, r, r1_dir, r1_hierarchy, related_rel_status
294
297
  WHERE r1_dir = "l"
295
298
  CREATE (n)
296
- <-[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status}]
299
+ <-[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r1_hierarchy}]
297
300
  -(r)
298
301
  }
299
302
  CALL {
300
- WITH r, p, r2_dir, related_rel_status
301
- WITH r, p, r2_dir, related_rel_status
303
+ WITH r, p, r2_dir, r2_hierarchy, related_rel_status
304
+ WITH r, p, r2_dir, r2_hierarchy, related_rel_status
302
305
  WHERE r2_dir = "r"
303
306
  CREATE (r)
304
- -[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status}]
307
+ -[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r2_hierarchy}]
305
308
  ->(p)
306
309
  }
307
310
  CALL {
308
- WITH r, p, r2_dir, related_rel_status
309
- WITH r, p, r2_dir, related_rel_status
311
+ WITH r, p, r2_dir, r2_hierarchy, related_rel_status
312
+ WITH r, p, r2_dir, r2_hierarchy, related_rel_status
310
313
  WHERE r2_dir = "l"
311
314
  CREATE (r)
312
- <-[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status}]
315
+ <-[:IS_RELATED {branch: $target_branch, branch_level: $branch_level, from: $at, status: related_rel_status, hierarchy: r2_hierarchy}]
313
316
  -(p)
314
317
  }
315
318
  }
@@ -1,4 +1,4 @@
1
- from typing import Any
1
+ from typing import Any, Iterable
2
2
 
3
3
  from infrahub.core.query import Query, QueryType
4
4
  from infrahub.database import InfrahubDatabase
@@ -42,6 +42,7 @@ CALL {
42
42
  }
43
43
  WITH DISTINCT diff_root AS diff_root
44
44
  WITH collect(diff_root) AS diff_roots
45
+ WHERE SIZE(diff_roots) = 2
45
46
  CALL {
46
47
  WITH diff_roots
47
48
  WITH diff_roots[0] AS base_diff_node, diff_roots[1] AS branch_diff_node
@@ -81,34 +82,59 @@ class EnrichedNodeBatchCreateQuery(Query):
81
82
  self.params = self._build_node_batch_params()
82
83
  query = """
83
84
  UNWIND $node_details_list AS node_details
84
- WITH node_details.root_uuid AS root_uuid, node_details.node_map AS node_map
85
+ WITH
86
+ node_details.root_uuid AS root_uuid,
87
+ node_details.node_map AS node_map,
88
+ toString(node_details.node_map.node_properties.uuid) AS node_uuid
89
+ MERGE (diff_root:DiffRoot {uuid: root_uuid})
90
+ MERGE (diff_root)-[:DIFF_HAS_NODE]->(diff_node:DiffNode {uuid: node_uuid})
91
+ WITH root_uuid, node_map, diff_node, (node_map.conflict_params IS NOT NULL) AS has_node_conflict
92
+ SET
93
+ diff_node.kind = node_map.node_properties.kind,
94
+ diff_node.label = node_map.node_properties.label,
95
+ diff_node.changed_at = node_map.node_properties.changed_at,
96
+ diff_node.action = node_map.node_properties.action,
97
+ diff_node.path_identifier = node_map.node_properties.path_identifier
98
+ WITH root_uuid, node_map, diff_node, has_node_conflict
85
99
  CALL {
86
- WITH root_uuid, node_map
87
- MATCH (diff_root {uuid: root_uuid})
88
- MERGE (diff_root)-[:DIFF_HAS_NODE]->(diff_node:DiffNode {uuid: node_map.node_properties.uuid})
89
- SET
90
- diff_node.kind = node_map.node_properties.kind,
91
- diff_node.label = node_map.node_properties.label,
92
- diff_node.changed_at = node_map.node_properties.changed_at,
93
- diff_node.action = node_map.node_properties.action,
94
- diff_node.path_identifier = node_map.node_properties.path_identifier
95
100
  // -------------------------
96
- // add/remove node-level conflict
101
+ // delete parent-child relationships for included nodes, they will be added in EnrichedNodesLinkQuery
97
102
  // -------------------------
98
- WITH diff_node, node_map
99
- OPTIONAL MATCH (diff_node)-[:DIFF_HAS_CONFLICT]->(current_diff_node_conflict:DiffConflict)
100
- WITH diff_node, node_map, current_diff_node_conflict, (node_map.conflict_params IS NOT NULL) AS has_node_conflict
101
- FOREACH (i in CASE WHEN has_node_conflict = FALSE THEN [1] ELSE [] END |
102
- DETACH DELETE current_diff_node_conflict
103
- )
104
- FOREACH (i in CASE WHEN has_node_conflict = TRUE THEN [1] ELSE [] END |
105
- MERGE (diff_node)-[:DIFF_HAS_CONFLICT]->(diff_node_conflict:DiffConflict)
106
- SET diff_node_conflict = node_map.conflict_params
107
- )
103
+ WITH diff_node
104
+ MATCH (diff_node)-[:DIFF_HAS_RELATIONSHIP]->(:DiffRelationship)-[parent_rel:DIFF_HAS_NODE]->(:DiffNode)
105
+ DELETE parent_rel
106
+ }
107
+ OPTIONAL MATCH (diff_node)-[:DIFF_HAS_CONFLICT]->(current_node_conflict:DiffConflict)
108
+ CALL {
109
+ // -------------------------
110
+ // create a node-level conflict, if necessary
111
+ // -------------------------
112
+ WITH diff_node, current_node_conflict, has_node_conflict
113
+ WITH diff_node, current_node_conflict, has_node_conflict
114
+ WHERE current_node_conflict IS NULL AND has_node_conflict = TRUE
115
+ CREATE (diff_node)-[:DIFF_HAS_CONFLICT]->(:DiffConflict)
116
+ }
117
+ CALL {
118
+ // -------------------------
119
+ // delete a node-level conflict, if necessary
120
+ // -------------------------
121
+ WITH current_node_conflict, has_node_conflict
122
+ WITH current_node_conflict, has_node_conflict
123
+ WHERE current_node_conflict IS NOT NULL AND has_node_conflict = FALSE
124
+ DETACH DELETE current_node_conflict
125
+ }
126
+ WITH root_uuid, node_map, diff_node, has_node_conflict, node_map.conflict_params AS node_conflict_params
127
+ CALL {
128
+ // -------------------------
129
+ // set the properties of the node-level conflict, if necessary
130
+ // -------------------------
131
+ WITH diff_node, has_node_conflict, node_conflict_params
132
+ WITH diff_node, has_node_conflict, node_conflict_params
133
+ WHERE has_node_conflict = TRUE
134
+ OPTIONAL MATCH (diff_node)-[:DIFF_HAS_CONFLICT]->(node_conflict:DiffConflict)
135
+ SET node_conflict = node_conflict_params
108
136
  }
109
137
  CALL {
110
- WITH root_uuid, node_map
111
- MATCH (diff_root {uuid: root_uuid})-[:DIFF_HAS_NODE]->(diff_node:DiffNode {uuid: node_map.node_properties.uuid})
112
138
  // -------------------------
113
139
  // remove stale attributes for this node
114
140
  // -------------------------
@@ -125,138 +151,131 @@ CALL {
125
151
  // -------------------------
126
152
  // add attributes for this node
127
153
  // -------------------------
128
- CALL {
129
- WITH diff_node, node_map
130
- UNWIND node_map.attributes AS node_attribute
131
- MERGE (diff_node)-[:DIFF_HAS_ATTRIBUTE]->(diff_attribute:DiffAttribute {name: node_attribute.node_properties.name})
132
- SET diff_attribute = node_attribute.node_properties
133
- // -------------------------
134
- // add properties for this attribute
135
- // -------------------------
136
- WITH diff_attribute, node_attribute
137
- // -------------------------
138
- // remove stale properties for this attribute
139
- // -------------------------
140
- CALL {
141
- WITH diff_attribute, node_attribute
142
- WITH diff_attribute, %(attr_props_list_comp)s AS prop_types
143
- OPTIONAL MATCH (diff_attribute)-[:DIFF_HAS_PROPERTY]->(prop_to_delete:DiffProperty)
144
- WHERE NOT (prop_to_delete.property_type IN prop_types)
145
- OPTIONAL MATCH (prop_to_delete)-[*..4]->(next_to_delete)
146
- DETACH DELETE next_to_delete
147
- DETACH DELETE prop_to_delete
148
- }
149
- UNWIND node_attribute.properties AS attr_property
150
- MERGE (diff_attribute)-[:DIFF_HAS_PROPERTY]->(diff_attr_prop:DiffProperty {property_type: attr_property.node_properties.property_type})
151
- SET diff_attr_prop = attr_property.node_properties
152
- // -------------------------
153
- // add/remove conflict for this property
154
- // -------------------------
155
- WITH diff_attr_prop, attr_property
156
- OPTIONAL MATCH (diff_attr_prop)-[:DIFF_HAS_CONFLICT]->(current_attr_prop_conflict:DiffConflict)
157
- WITH diff_attr_prop, attr_property, current_attr_prop_conflict, (attr_property.conflict_params IS NOT NULL) AS has_prop_conflict
158
- FOREACH (i in CASE WHEN has_prop_conflict = FALSE THEN [1] ELSE [] END |
159
- DETACH DELETE current_attr_prop_conflict
160
- )
161
- FOREACH (i in CASE WHEN has_prop_conflict = TRUE THEN [1] ELSE [] END |
162
- MERGE (diff_attr_prop)-[:DIFF_HAS_CONFLICT]->(diff_attr_prop_conflict:DiffConflict)
163
- SET diff_attr_prop_conflict = attr_property.conflict_params
164
- )
165
- }
154
+ UNWIND node_map.attributes AS node_attribute
155
+ MERGE (diff_node)-[:DIFF_HAS_ATTRIBUTE]->(diff_attribute:DiffAttribute {name: node_attribute.node_properties.name})
156
+ SET diff_attribute = node_attribute.node_properties
166
157
  // -------------------------
167
- // remove stale relationships for this node
158
+ // add properties for this attribute
159
+ // -------------------------
160
+ WITH diff_attribute, node_attribute
161
+ // -------------------------
162
+ // remove stale properties for this attribute
168
163
  // -------------------------
169
- WITH diff_node, node_map
170
164
  CALL {
171
- WITH diff_node, node_map
172
- WITH diff_node, %(rel_name_list_comp)s AS rel_names
173
- OPTIONAL MATCH (diff_node)-[:DIFF_HAS_RELATIONSHIP]->(rel_to_delete:DiffRelationship)
174
- WHERE NOT (rel_to_delete.name IN rel_names)
175
- OPTIONAL MATCH (rel_to_delete)-[*..8]->(next_to_delete)
165
+ WITH diff_attribute, node_attribute
166
+ WITH diff_attribute, %(attr_props_list_comp)s AS prop_types
167
+ OPTIONAL MATCH (diff_attribute)-[:DIFF_HAS_PROPERTY]->(prop_to_delete:DiffProperty)
168
+ WHERE NOT (prop_to_delete.property_type IN prop_types)
169
+ OPTIONAL MATCH (prop_to_delete)-[*..4]->(next_to_delete)
176
170
  DETACH DELETE next_to_delete
177
- DETACH DELETE rel_to_delete
171
+ DETACH DELETE prop_to_delete
178
172
  }
173
+ UNWIND node_attribute.properties AS attr_property
174
+ MERGE (diff_attribute)-[:DIFF_HAS_PROPERTY]->(diff_attr_prop:DiffProperty {property_type: attr_property.node_properties.property_type})
175
+ SET diff_attr_prop = attr_property.node_properties
179
176
  // -------------------------
180
- // add relationships for this node
177
+ // add/remove conflict for this property
181
178
  // -------------------------
179
+ WITH diff_attr_prop, attr_property
180
+ OPTIONAL MATCH (diff_attr_prop)-[:DIFF_HAS_CONFLICT]->(current_attr_prop_conflict:DiffConflict)
181
+ WITH diff_attr_prop, attr_property, current_attr_prop_conflict, (attr_property.conflict_params IS NOT NULL) AS has_prop_conflict
182
+ FOREACH (i in CASE WHEN has_prop_conflict = FALSE THEN [1] ELSE [] END |
183
+ DETACH DELETE current_attr_prop_conflict
184
+ )
185
+ FOREACH (i in CASE WHEN has_prop_conflict = TRUE THEN [1] ELSE [] END |
186
+ MERGE (diff_attr_prop)-[:DIFF_HAS_CONFLICT]->(diff_attr_prop_conflict:DiffConflict)
187
+ SET diff_attr_prop_conflict = attr_property.conflict_params
188
+ )
189
+ }
190
+ // -------------------------
191
+ // remove stale relationships for this node
192
+ // -------------------------
193
+ CALL {
182
194
  WITH diff_node, node_map
183
- CALL {
184
- WITH diff_node, node_map
185
- UNWIND node_map.relationships as node_relationship
186
- MERGE (diff_node)-[:DIFF_HAS_RELATIONSHIP]->(diff_relationship:DiffRelationship {name: node_relationship.node_properties.name})
187
- SET diff_relationship = node_relationship.node_properties
188
- // -------------------------
189
- // remove stale elements for this relationship group
190
- // -------------------------
191
- WITH diff_relationship, node_relationship
192
- CALL {
193
- WITH diff_relationship, node_relationship
194
- WITH diff_relationship, %(rel_peers_list_comp)s AS rel_peers
195
- OPTIONAL MATCH (diff_relationship)-[:DIFF_HAS_ELEMENT]->(element_to_delete:DiffRelationshipElement)
196
- WHERE NOT (element_to_delete.peer_id IN rel_peers)
197
- OPTIONAL MATCH (element_to_delete)-[*..6]->(next_to_delete)
198
- DETACH DELETE next_to_delete
199
- DETACH DELETE element_to_delete
200
- }
201
- // -------------------------
202
- // add elements for this relationship group
203
- // -------------------------
204
- WITH diff_relationship, node_relationship
205
- UNWIND node_relationship.relationships as node_single_relationship
206
- MERGE (diff_relationship)-[:DIFF_HAS_ELEMENT]
207
- ->(diff_relationship_element:DiffRelationshipElement {peer_id: node_single_relationship.node_properties.peer_id})
208
- SET diff_relationship_element = node_single_relationship.node_properties
209
- // -------------------------
210
- // add/remove conflict for this relationship element
211
- // -------------------------
212
- WITH diff_relationship_element, node_single_relationship
213
- OPTIONAL MATCH (diff_relationship_element)-[:DIFF_HAS_CONFLICT]->(current_element_conflict:DiffConflict)
214
- WITH diff_relationship_element, node_single_relationship, current_element_conflict,
215
- (node_single_relationship.conflict_params IS NOT NULL) AS has_element_conflict
216
- FOREACH (i in CASE WHEN has_element_conflict = FALSE THEN [1] ELSE [] END |
217
- DETACH DELETE current_element_conflict
218
- )
219
- FOREACH (i in CASE WHEN has_element_conflict = TRUE THEN [1] ELSE [] END |
220
- MERGE (diff_relationship_element)-[:DIFF_HAS_CONFLICT]->(element_conflict:DiffConflict)
221
- SET element_conflict = node_single_relationship.conflict_params
222
- )
223
- // -------------------------
224
- // remove stale properties for this relationship element
225
- // -------------------------
226
- WITH diff_relationship_element, node_single_relationship
227
- CALL {
228
- WITH diff_relationship_element, node_single_relationship
229
- WITH diff_relationship_element, %(element_props_list_comp)s AS element_props
230
- OPTIONAL MATCH (diff_relationship_element)-[:DIFF_HAS_PROPERTY]->(property_to_delete:DiffProperty)
231
- WHERE NOT (property_to_delete.property_type IN element_props)
232
- OPTIONAL MATCH (property_to_delete)-[*..4]->(next_to_delete)
233
- DETACH DELETE next_to_delete
234
- DETACH DELETE property_to_delete
235
- }
236
- // -------------------------
237
- // add properties for this relationship element
238
- // -------------------------
239
- WITH diff_relationship_element, node_single_relationship
240
- UNWIND node_single_relationship.properties as node_relationship_property
241
- MERGE (diff_relationship_element)-[:DIFF_HAS_PROPERTY]
242
- ->(diff_relationship_property:DiffProperty {property_type: node_relationship_property.node_properties.property_type})
243
- SET diff_relationship_property = node_relationship_property.node_properties
244
- // -------------------------
245
- // add conflict for this relationship element
246
- // -------------------------
247
- WITH diff_relationship_property, node_relationship_property
248
- OPTIONAL MATCH (diff_relationship_property)-[:DIFF_HAS_CONFLICT]->(diff_relationship_property_conflict:DiffConflict)
249
- WITH diff_relationship_property, node_relationship_property, diff_relationship_property_conflict,
250
- (node_relationship_property.conflict_params IS NOT NULL) AS has_property_conflict
251
- FOREACH (i in CASE WHEN has_property_conflict = FALSE THEN [1] ELSE [] END |
252
- DETACH DELETE diff_relationship_property_conflict
253
- )
254
- FOREACH (i in CASE WHEN has_property_conflict = TRUE THEN [1] ELSE [] END |
255
- MERGE (diff_relationship_property)-[:DIFF_HAS_CONFLICT]->(property_conflict:DiffConflict)
256
- SET property_conflict = node_relationship_property.conflict_params
257
- )
258
- }
195
+ WITH diff_node, %(rel_name_list_comp)s AS rel_names
196
+ OPTIONAL MATCH (diff_node)-[:DIFF_HAS_RELATIONSHIP]->(rel_to_delete:DiffRelationship)
197
+ WHERE NOT (rel_to_delete.name IN rel_names)
198
+ OPTIONAL MATCH (rel_to_delete)-[*..8]->(next_to_delete)
199
+ DETACH DELETE next_to_delete
200
+ DETACH DELETE rel_to_delete
259
201
  }
202
+ // -------------------------
203
+ // add relationships for this node
204
+ // -------------------------
205
+ WITH diff_node, node_map
206
+ UNWIND node_map.relationships as node_relationship
207
+ MERGE (diff_node)-[:DIFF_HAS_RELATIONSHIP]->(diff_relationship:DiffRelationship {name: node_relationship.node_properties.name})
208
+ SET diff_relationship = node_relationship.node_properties
209
+ // -------------------------
210
+ // remove stale elements for this relationship group
211
+ // -------------------------
212
+ WITH diff_relationship, node_relationship
213
+ CALL {
214
+ WITH diff_relationship, node_relationship
215
+ WITH diff_relationship, %(rel_peers_list_comp)s AS rel_peers
216
+ OPTIONAL MATCH (diff_relationship)-[:DIFF_HAS_ELEMENT]->(element_to_delete:DiffRelationshipElement)
217
+ WHERE NOT (element_to_delete.peer_id IN rel_peers)
218
+ OPTIONAL MATCH (element_to_delete)-[*..6]->(next_to_delete)
219
+ DETACH DELETE next_to_delete
220
+ DETACH DELETE element_to_delete
221
+ }
222
+ // -------------------------
223
+ // add elements for this relationship group
224
+ // -------------------------
225
+ WITH diff_relationship, node_relationship
226
+ UNWIND node_relationship.relationships as node_single_relationship
227
+ MERGE (diff_relationship)-[:DIFF_HAS_ELEMENT]
228
+ ->(diff_relationship_element:DiffRelationshipElement {peer_id: node_single_relationship.node_properties.peer_id})
229
+ SET diff_relationship_element = node_single_relationship.node_properties
230
+ // -------------------------
231
+ // add/remove conflict for this relationship element
232
+ // -------------------------
233
+ WITH diff_relationship_element, node_single_relationship
234
+ OPTIONAL MATCH (diff_relationship_element)-[:DIFF_HAS_CONFLICT]->(current_element_conflict:DiffConflict)
235
+ WITH diff_relationship_element, node_single_relationship, current_element_conflict,
236
+ (node_single_relationship.conflict_params IS NOT NULL) AS has_element_conflict
237
+ FOREACH (i in CASE WHEN has_element_conflict = FALSE THEN [1] ELSE [] END |
238
+ DETACH DELETE current_element_conflict
239
+ )
240
+ FOREACH (i in CASE WHEN has_element_conflict = TRUE THEN [1] ELSE [] END |
241
+ MERGE (diff_relationship_element)-[:DIFF_HAS_CONFLICT]->(element_conflict:DiffConflict)
242
+ SET element_conflict = node_single_relationship.conflict_params
243
+ )
244
+ // -------------------------
245
+ // remove stale properties for this relationship element
246
+ // -------------------------
247
+ WITH diff_relationship_element, node_single_relationship
248
+ CALL {
249
+ WITH diff_relationship_element, node_single_relationship
250
+ WITH diff_relationship_element, %(element_props_list_comp)s AS element_props
251
+ OPTIONAL MATCH (diff_relationship_element)-[:DIFF_HAS_PROPERTY]->(property_to_delete:DiffProperty)
252
+ WHERE NOT (property_to_delete.property_type IN element_props)
253
+ OPTIONAL MATCH (property_to_delete)-[*..4]->(next_to_delete)
254
+ DETACH DELETE next_to_delete
255
+ DETACH DELETE property_to_delete
256
+ }
257
+ // -------------------------
258
+ // add properties for this relationship element
259
+ // -------------------------
260
+ WITH diff_relationship_element, node_single_relationship
261
+ UNWIND node_single_relationship.properties as node_relationship_property
262
+ MERGE (diff_relationship_element)-[:DIFF_HAS_PROPERTY]
263
+ ->(diff_relationship_property:DiffProperty {property_type: node_relationship_property.node_properties.property_type})
264
+ SET diff_relationship_property = node_relationship_property.node_properties
265
+ // -------------------------
266
+ // add conflict for this relationship element
267
+ // -------------------------
268
+ WITH diff_relationship_property, node_relationship_property
269
+ OPTIONAL MATCH (diff_relationship_property)-[:DIFF_HAS_CONFLICT]->(diff_relationship_property_conflict:DiffConflict)
270
+ WITH diff_relationship_property, node_relationship_property, diff_relationship_property_conflict,
271
+ (node_relationship_property.conflict_params IS NOT NULL) AS has_property_conflict
272
+ FOREACH (i in CASE WHEN has_property_conflict = FALSE THEN [1] ELSE [] END |
273
+ DETACH DELETE diff_relationship_property_conflict
274
+ )
275
+ FOREACH (i in CASE WHEN has_property_conflict = TRUE THEN [1] ELSE [] END |
276
+ MERGE (diff_relationship_property)-[:DIFF_HAS_CONFLICT]->(property_conflict:DiffConflict)
277
+ SET property_conflict = node_relationship_property.conflict_params
278
+ )
260
279
  """ % {
261
280
  "attr_name_list_comp": db.render_list_comprehension(
262
281
  items="node_map.attributes", item_name="node_properties.name"
@@ -409,47 +428,34 @@ class EnrichedNodesLinkQuery(Query):
409
428
  type = QueryType.WRITE
410
429
  insert_return = False
411
430
 
412
- def __init__(self, enriched_diffs: EnrichedDiffs, **kwargs: Any) -> None:
431
+ def __init__(self, diff_root_uuid: str, diff_nodes: Iterable[EnrichedDiffNode], **kwargs: Any) -> None:
413
432
  super().__init__(**kwargs)
414
- self.enriched_diffs = enriched_diffs
433
+ self.diff_root_uuid = diff_root_uuid
434
+ self.diff_nodes = diff_nodes
415
435
 
416
436
  async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
417
- parent_links_list = []
418
- for diff_root in (self.enriched_diffs.base_branch_diff, self.enriched_diffs.diff_branch_diff):
419
- for node in diff_root.nodes:
420
- parent_links_list.extend(self._build_node_parent_links(enriched_node=node, root_uuid=diff_root.uuid))
421
- self.params = {"node_links_list": parent_links_list}
437
+ parent_node_map: dict[str, dict[str, str]] = {}
438
+ for diff_node in self.diff_nodes:
439
+ if diff_node.uuid not in parent_node_map:
440
+ parent_node_map[diff_node.uuid] = {}
441
+ for relationship in diff_node.relationships:
442
+ for parent_node in relationship.nodes:
443
+ parent_node_map[diff_node.uuid][relationship.name] = parent_node.uuid
444
+ self.params = {"root_uuid": self.diff_root_uuid, "parent_node_map": parent_node_map}
422
445
  query = """
423
- UNWIND $node_links_list AS node_link_details
424
- WITH
425
- node_link_details.root_uuid AS root_uuid,
426
- node_link_details.parent_uuid AS parent_uuid,
427
- node_link_details.child_uuid AS child_uuid,
428
- node_link_details.relationship_name AS relationship_name
446
+ WITH keys($parent_node_map) AS child_node_uuids
447
+ MATCH (diff_root:DiffRoot {uuid: $root_uuid})
448
+ MATCH (diff_root)-[:DIFF_HAS_NODE]->(child_node:DiffNode)
449
+ WHERE child_node.uuid IN child_node_uuids
429
450
  CALL {
430
- WITH root_uuid, parent_uuid, child_uuid, relationship_name
431
- MATCH (diff_root {uuid: root_uuid})
451
+ WITH diff_root, child_node
452
+ WITH diff_root, child_node, $parent_node_map[child_node.uuid] AS sub_map
453
+ WITH diff_root, child_node, sub_map, keys(sub_map) AS relationship_names
454
+ MATCH (child_node)-[:DIFF_HAS_RELATIONSHIP]->(diff_rel_group:DiffRelationship)
455
+ WHERE diff_rel_group.name IN relationship_names
456
+ WITH diff_root, diff_rel_group, toString(sub_map[diff_rel_group.name]) AS parent_uuid
432
457
  MATCH (diff_root)-[:DIFF_HAS_NODE]->(parent_node:DiffNode {uuid: parent_uuid})
433
- -[:DIFF_HAS_RELATIONSHIP]->(diff_rel_group:DiffRelationship {name: relationship_name})
434
- MATCH (diff_root)-[:DIFF_HAS_NODE]->(child_node:DiffNode {uuid: child_uuid})
435
- MERGE (diff_rel_group)-[:DIFF_HAS_NODE]->(child_node)
458
+ MERGE (diff_rel_group)-[:DIFF_HAS_NODE]->(parent_node)
436
459
  }
437
460
  """
438
461
  self.add_to_query(query)
439
-
440
- def _build_node_parent_links(self, enriched_node: EnrichedDiffNode, root_uuid: str) -> list[dict[str, str]]:
441
- if not enriched_node.relationships:
442
- return []
443
- parent_links = []
444
- for relationship in enriched_node.relationships:
445
- for child_node in relationship.nodes:
446
- parent_links.append(
447
- {
448
- "parent_uuid": enriched_node.uuid,
449
- "relationship_name": relationship.name,
450
- "child_uuid": child_node.uuid,
451
- "root_uuid": root_uuid,
452
- }
453
- )
454
- parent_links.extend(self._build_node_parent_links(enriched_node=child_node, root_uuid=root_uuid))
455
- return parent_links
@@ -6,10 +6,10 @@ from infrahub.database import InfrahubDatabase
6
6
  from ..model.path import TrackingId
7
7
 
8
8
 
9
- class DiffSummaryCountsEnricherQuery(Query):
10
- """Update summary counters for a given diff"""
9
+ class DiffFieldsSummaryCountsEnricherQuery(Query):
10
+ """Update summary counters for the attributes and relationshipsin in a diff"""
11
11
 
12
- name = "diff_summary_count_enricher"
12
+ name = "diff_fields_summary_count_enricher"
13
13
  type = QueryType.WRITE
14
14
  insert_return = False
15
15
 
@@ -23,7 +23,9 @@ class DiffSummaryCountsEnricherQuery(Query):
23
23
  ) -> None:
24
24
  super().__init__(**kwargs)
25
25
  if (diff_id is None and tracking_id is None) or (diff_id and tracking_id):
26
- raise ValueError("EnrichedDiffAllConflictsQuery requires one and only one of `tracking_id` or `diff_id`")
26
+ raise ValueError(
27
+ "DiffFieldsSummaryCountsEnricherQuery requires one and only one of `tracking_id` or `diff_id`"
28
+ )
27
29
  self.diff_branch_name = diff_branch_name
28
30
  self.tracking_id = tracking_id
29
31
  self.diff_id = diff_id
@@ -138,6 +140,51 @@ CALL {
138
140
  SET dr.num_removed = num_removed
139
141
  }
140
142
  }
143
+ """
144
+ self.add_to_query(query)
145
+
146
+
147
+ class DiffNodesSummaryCountsEnricherQuery(Query):
148
+ """Update summary counters for the nodes and root in a diff"""
149
+
150
+ name = "diff_nodes_summary_count_enricher"
151
+ type = QueryType.WRITE
152
+ insert_return = False
153
+
154
+ def __init__(
155
+ self,
156
+ diff_branch_name: str,
157
+ tracking_id: TrackingId | None = None,
158
+ diff_id: str | None = None,
159
+ node_uuids: list[str] | None = None,
160
+ **kwargs: Any,
161
+ ) -> None:
162
+ super().__init__(**kwargs)
163
+ if (diff_id is None and tracking_id is None) or (diff_id and tracking_id):
164
+ raise ValueError(
165
+ "DiffNodesSummaryCountsEnricherQuery requires one and only one of `tracking_id` or `diff_id`"
166
+ )
167
+ self.diff_branch_name = diff_branch_name
168
+ self.tracking_id = tracking_id
169
+ self.diff_id = diff_id
170
+ if self.tracking_id is None and self.diff_id is None:
171
+ raise RuntimeError("tracking_id or diff_id is required")
172
+ self.node_uuids = node_uuids
173
+
174
+ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None: # noqa: ARG002
175
+ self.params = {
176
+ "diff_branch_name": self.diff_branch_name,
177
+ "diff_id": self.diff_id,
178
+ "tracking_id": self.tracking_id.serialize() if self.tracking_id else None,
179
+ "node_uuids": self.node_uuids,
180
+ }
181
+
182
+ query = """
183
+ MATCH (root:DiffRoot)
184
+ WHERE ($diff_id IS NOT NULL AND root.uuid = $diff_id)
185
+ OR ($tracking_id IS NOT NULL AND root.tracking_id = $tracking_id AND root.diff_branch = $diff_branch_name)
186
+ MATCH (root)-[:DIFF_HAS_NODE]->(dn:DiffNode)
187
+ WHERE $node_uuids IS NULL OR dn.uuid IN $node_uuids
141
188
  // ----------------------
142
189
  // handle node count updates
143
190
  // ----------------------
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from collections import defaultdict
4
4
  from dataclasses import dataclass, field
5
- from typing import TYPE_CHECKING, Any, Optional
5
+ from typing import TYPE_CHECKING, Any
6
6
  from uuid import uuid4
7
7
 
8
8
  from infrahub.core.constants import (
@@ -99,7 +99,7 @@ class DiffPropertyIntermediate:
99
99
  return self._ordered_values
100
100
 
101
101
  @property
102
- def earliest_diff_value(self) -> Optional[DiffValueIntermediate]:
102
+ def earliest_diff_value(self) -> DiffValueIntermediate | None:
103
103
  ordered_values = self.get_ordered_values_asc()
104
104
  if not ordered_values:
105
105
  return None
@@ -461,7 +461,7 @@ class DiffQueryParser:
461
461
  diff_branch: Branch,
462
462
  schema_manager: SchemaManager,
463
463
  from_time: Timestamp,
464
- to_time: Optional[Timestamp] = None,
464
+ to_time: Timestamp | None = None,
465
465
  previous_node_field_specifiers: dict[str, set[str]] | None = None,
466
466
  ) -> None:
467
467
  self.base_branch_name = base_branch.name
@@ -733,7 +733,7 @@ class DiffQueryParser:
733
733
  base_property_set = base_diff_relationship.properties_by_db_id.get(db_id)
734
734
  if not base_property_set:
735
735
  continue
736
- base_diff_property_by_type: dict[DatabaseEdgeType, Optional[DiffRelationshipPropertyIntermediate]] = {
736
+ base_diff_property_by_type: dict[DatabaseEdgeType, DiffRelationshipPropertyIntermediate | None] = {
737
737
  DatabaseEdgeType(p.property_type): None for p in property_set
738
738
  }
739
739
  base_diff_property_by_type[DatabaseEdgeType.IS_RELATED] = None