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
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  from collections import defaultdict
5
- from typing import TYPE_CHECKING, Optional, Union
5
+ from typing import TYPE_CHECKING
6
6
 
7
7
  from typing_extensions import Self
8
8
 
@@ -35,12 +35,12 @@ class BranchDiffer:
35
35
  def __init__(
36
36
  self,
37
37
  branch: Branch,
38
- origin_branch: Optional[Branch] = None,
38
+ origin_branch: Branch | None = None,
39
39
  branch_only: bool = False,
40
- diff_from: Optional[Union[str, Timestamp]] = None,
41
- diff_to: Optional[Union[str, Timestamp]] = None,
42
- db: Optional[InfrahubDatabase] = None,
43
- service: Optional[InfrahubServices] = None,
40
+ diff_from: str | Timestamp | None = None,
41
+ diff_to: str | Timestamp | None = None,
42
+ db: InfrahubDatabase | None = None,
43
+ service: InfrahubServices | None = None,
44
44
  ):
45
45
  """_summary_
46
46
 
@@ -81,7 +81,7 @@ class BranchDiffer:
81
81
 
82
82
  # Results organized by Branch
83
83
  self._results: dict[str, dict] = defaultdict(lambda: {"nodes": {}, "rels": defaultdict(dict), "files": {}})
84
- self._calculated_diff_files_at: Optional[Timestamp] = None
84
+ self._calculated_diff_files_at: Timestamp | None = None
85
85
 
86
86
  @property
87
87
  def service(self) -> InfrahubServices:
@@ -101,9 +101,9 @@ class BranchDiffer:
101
101
  db: InfrahubDatabase,
102
102
  branch: Branch,
103
103
  branch_only: bool = False,
104
- diff_from: Optional[Union[str, Timestamp]] = None,
105
- diff_to: Optional[Union[str, Timestamp]] = None,
106
- service: Optional[InfrahubServices] = None,
104
+ diff_from: str | Timestamp | None = None,
105
+ diff_to: str | Timestamp | None = None,
106
+ service: InfrahubServices | None = None,
107
107
  ) -> Self:
108
108
  origin_branch = branch.get_origin_branch()
109
109
 
@@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, Any
3
3
  from infrahub.core.constants import NULL_VALUE, DiffAction, RelationshipCardinality
4
4
  from infrahub.core.constants.database import DatabaseEdgeType
5
5
  from infrahub.database import InfrahubDatabase
6
+ from infrahub.log import get_logger
6
7
 
7
8
  from ..model.path import (
8
9
  CalculatedDiffs,
@@ -16,6 +17,8 @@ from .interface import DiffEnricherInterface
16
17
  if TYPE_CHECKING:
17
18
  from infrahub.core.schema import MainSchemaTypes
18
19
 
20
+ log = get_logger()
21
+
19
22
 
20
23
  class DiffCardinalityOneEnricher(DiffEnricherInterface):
21
24
  """Clean up diffs for cardinality=one relationships to make them cleaner and more intuitive
@@ -34,6 +37,7 @@ class DiffCardinalityOneEnricher(DiffEnricherInterface):
34
37
 
35
38
  async def enrich(self, enriched_diff_root: EnrichedDiffRoot, calculated_diffs: CalculatedDiffs) -> None: # noqa: ARG002
36
39
  self._node_schema_map = {}
40
+ log.info("Beginning cardinality-one diff enrichment...")
37
41
  for diff_node in enriched_diff_root.nodes:
38
42
  for relationship_group in diff_node.relationships:
39
43
  if (
@@ -41,6 +45,7 @@ class DiffCardinalityOneEnricher(DiffEnricherInterface):
41
45
  and len(relationship_group.relationships) > 0
42
46
  ):
43
47
  self.consolidate_cardinality_one_diff_elements(diff_relationship=relationship_group)
48
+ log.info("Cardinality-one diff enrichment complete.")
44
49
 
45
50
  def _determine_action(self, previous_value: Any, new_value: Any) -> DiffAction:
46
51
  if previous_value == new_value:
@@ -7,19 +7,24 @@ from infrahub.core.query.node import NodeGetHierarchyQuery
7
7
  from infrahub.core.query.relationship import RelationshipGetPeerQuery, RelationshipPeerData
8
8
  from infrahub.core.schema import ProfileSchema, TemplateSchema
9
9
  from infrahub.database import InfrahubDatabase
10
+ from infrahub.log import get_logger
10
11
 
11
12
  from ..model.path import (
12
13
  CalculatedDiffs,
13
14
  EnrichedDiffRoot,
14
15
  )
16
+ from ..parent_node_adder import DiffParentNodeAdder, ParentNodeAddRequest
15
17
  from .interface import DiffEnricherInterface
16
18
 
19
+ log = get_logger()
20
+
17
21
 
18
22
  class DiffHierarchyEnricher(DiffEnricherInterface):
19
23
  """Add hierarchy and parent/component nodes to diff even if the higher-level nodes are unchanged"""
20
24
 
21
- def __init__(self, db: InfrahubDatabase):
25
+ def __init__(self, db: InfrahubDatabase, parent_adder: DiffParentNodeAdder):
22
26
  self.db = db
27
+ self.parent_adder = parent_adder
23
28
 
24
29
  async def enrich(
25
30
  self,
@@ -30,6 +35,8 @@ class DiffHierarchyEnricher(DiffEnricherInterface):
30
35
  # - A node has a relationship of kind parent
31
36
  # - A node is part of a hierarchy
32
37
 
38
+ log.info("Beginning hierarchical diff enrichment...")
39
+ self.parent_adder.initialize(enriched_diff_root=enriched_diff_root)
33
40
  node_rel_parent_map: dict[str, list[str]] = defaultdict(list)
34
41
  node_hierarchy_map: dict[str, list[str]] = defaultdict(list)
35
42
 
@@ -55,6 +62,7 @@ class DiffHierarchyEnricher(DiffEnricherInterface):
55
62
 
56
63
  await self._enrich_nodes_with_parent(enriched_diff_root=enriched_diff_root, node_map=node_rel_parent_map)
57
64
  await self._enrich_hierarchical_nodes(enriched_diff_root=enriched_diff_root, node_map=node_hierarchy_map)
65
+ log.info("Hierarchical diff enrichment complete.")
58
66
 
59
67
  async def _enrich_hierarchical_nodes(
60
68
  self,
@@ -65,6 +73,7 @@ class DiffHierarchyEnricher(DiffEnricherInterface):
65
73
 
66
74
  # Retrieve the ID of all ancestors
67
75
  for kind, node_ids in node_map.items():
76
+ log.info(f"Beginning hierarchy enrichment for {kind} node, num_nodes={len(node_ids)}...")
68
77
  hierarchy_schema = self.db.schema.get(
69
78
  name=kind, branch=enriched_diff_root.diff_branch_name, duplicate=False
70
79
  )
@@ -89,7 +98,7 @@ class DiffHierarchyEnricher(DiffEnricherInterface):
89
98
 
90
99
  current_node = node
91
100
  for ancestor in ancestors:
92
- parent = enriched_diff_root.add_parent(
101
+ parent_request = ParentNodeAddRequest(
93
102
  node_id=current_node.uuid,
94
103
  parent_id=str(ancestor.uuid),
95
104
  parent_kind=ancestor.kind,
@@ -99,6 +108,7 @@ class DiffHierarchyEnricher(DiffEnricherInterface):
99
108
  parent_rel_cardinality=parent_rel.cardinality,
100
109
  parent_rel_label=parent_rel.label or "",
101
110
  )
111
+ parent = self.parent_adder.add_parent(parent_request=parent_request)
102
112
 
103
113
  current_node = parent
104
114
 
@@ -116,6 +126,7 @@ class DiffHierarchyEnricher(DiffEnricherInterface):
116
126
 
117
127
  # Query the UUID of the parent
118
128
  for kind, ids in node_map.items():
129
+ log.info(f"Beginning parent enrichment for {kind} node, num_nodes={len(ids)}...")
119
130
  schema_node = self.db.schema.get(name=kind, branch=enriched_diff_root.diff_branch_name, duplicate=False)
120
131
 
121
132
  parent_rel = [rel for rel in schema_node.relationships if rel.kind == RelationshipKind.PARENT][0]
@@ -140,15 +151,16 @@ class DiffHierarchyEnricher(DiffEnricherInterface):
140
151
  # Check if the parent are already present
141
152
  # If parent is already in the list of node we need to add a relationship
142
153
  # If parent is not in the list of node, we need to add it
154
+ diff_node_map = enriched_diff_root.get_node_map(node_uuids=set(parent_peers.keys()))
143
155
  for node_id, peer_parent in parent_peers.items():
144
156
  # TODO check if we can optimize this part to avoid querying this multiple times
145
- node = enriched_diff_root.get_node(node_uuid=node_id)
157
+ node = diff_node_map[node_id]
146
158
  schema_node = self.db.schema.get(
147
159
  name=node.kind, branch=enriched_diff_root.diff_branch_name, duplicate=False
148
160
  )
149
161
  parent_rel = [rel for rel in schema_node.relationships if rel.kind == RelationshipKind.PARENT][0]
150
162
 
151
- enriched_diff_root.add_parent(
163
+ parent_request = ParentNodeAddRequest(
152
164
  node_id=node.uuid,
153
165
  parent_id=str(peer_parent.peer_id),
154
166
  parent_kind=peer_parent.peer_kind,
@@ -158,6 +170,7 @@ class DiffHierarchyEnricher(DiffEnricherInterface):
158
170
  parent_rel_cardinality=parent_rel.cardinality,
159
171
  parent_rel_label=parent_rel.label or "",
160
172
  )
173
+ self.parent_adder.add_parent(parent_request=parent_request)
161
174
 
162
175
  if node_parent_with_parent_map:
163
176
  await self._enrich_nodes_with_parent(
@@ -6,6 +6,7 @@ from infrahub.core.constants import DiffAction
6
6
  from infrahub.core.constants.database import DatabaseEdgeType
7
7
  from infrahub.core.query.node import NodeGetKindQuery
8
8
  from infrahub.database import InfrahubDatabase
9
+ from infrahub.log import get_logger
9
10
 
10
11
  from ..model.path import (
11
12
  CalculatedDiffs,
@@ -17,6 +18,8 @@ from ..model.path import (
17
18
  from ..payload_builder import get_display_labels
18
19
  from .interface import DiffEnricherInterface
19
20
 
21
+ log = get_logger()
22
+
20
23
  PROPERTY_TYPES_WITH_LABELS = {DatabaseEdgeType.IS_RELATED, DatabaseEdgeType.HAS_OWNER, DatabaseEdgeType.HAS_SOURCE}
21
24
 
22
25
 
@@ -194,6 +197,7 @@ class DiffLabelsEnricher(DiffEnricherInterface):
194
197
  calculated_diffs: CalculatedDiffs | None = None, # noqa: ARG002
195
198
  conflicts_only: bool = False,
196
199
  ) -> None:
200
+ log.info("Beginning display labels diff enrichment...")
197
201
  self._base_branch_name = enriched_diff_root.base_branch_name
198
202
  self._diff_branch_name = enriched_diff_root.diff_branch_name
199
203
  self._conflicts_only = conflicts_only
@@ -214,3 +218,4 @@ class DiffLabelsEnricher(DiffEnricherInterface):
214
218
  ...
215
219
 
216
220
  self._update_relationship_labels(enriched_diff=enriched_diff_root)
221
+ log.info("Display labels diff enrichment complete.")
@@ -1,10 +1,13 @@
1
1
  from infrahub.core.constants import PathType
2
2
  from infrahub.core.path import DataPath
3
3
  from infrahub.database import InfrahubDatabase
4
+ from infrahub.log import get_logger
4
5
 
5
6
  from ..model.path import CalculatedDiffs, EnrichedDiffRoot
6
7
  from .interface import DiffEnricherInterface
7
8
 
9
+ log = get_logger()
10
+
8
11
 
9
12
  class DiffPathIdentifierEnricher(DiffEnricherInterface):
10
13
  """Add path identifiers to every element in the diff"""
@@ -62,3 +65,4 @@ class DiffPathIdentifierEnricher(DiffEnricherInterface):
62
65
  relationship_property_path = relationship_element_path.model_copy()
63
66
  relationship_property_path.property_name = relationship_property.property_type.value
64
67
  relationship_property.path_identifier = relationship_property_path.get_path(with_peer=False)
68
+ log.info("Path identifier diff enrichment complete.")
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
 
4
3
  from infrahub.core.constants import DiffAction
5
4
  from infrahub.core.constants.database import DatabaseEdgeType
@@ -18,8 +17,8 @@ class ChangedIpamNodeDetails:
18
17
  node_uuid: str
19
18
  is_address: bool
20
19
  is_delete: bool
21
- namespace_id: Optional[str]
22
- ip_value: Optional[str]
20
+ namespace_id: str | None
21
+ ip_value: str | None
23
22
 
24
23
 
25
24
  class IpamDiffParser:
@@ -142,7 +141,7 @@ class IpamDiffParser:
142
141
  uuids_missing_data=uuids_missing_data,
143
142
  )
144
143
 
145
- def _get_ip_value(self, node_diff: EnrichedDiffNode) -> Optional[str]:
144
+ def _get_ip_value(self, node_diff: EnrichedDiffNode) -> str | None:
146
145
  ip_attr_diff = None
147
146
  for diff_attr in node_diff.attributes:
148
147
  if diff_attr.name in {"prefix", "address"}:
@@ -155,7 +154,7 @@ class IpamDiffParser:
155
154
  return diff_property.new_value or diff_property.previous_value
156
155
  return None
157
156
 
158
- def _get_namespace_id(self, node_diff: EnrichedDiffNode) -> Optional[str]:
157
+ def _get_namespace_id(self, node_diff: EnrichedDiffNode) -> str | None:
159
158
  namespace_rel = None
160
159
  for diff_rel in node_diff.relationships:
161
160
  if diff_rel.name == "ip_namespace":
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from enum import Enum
4
- from typing import Any, Optional
4
+ from typing import Any
5
5
 
6
6
  from pydantic import BaseModel, ConfigDict, Field
7
7
 
@@ -46,8 +46,8 @@ class BaseDiffElement(BaseModel):
46
46
 
47
47
 
48
48
  class ValueElement(BaseDiffElement):
49
- previous: Optional[Any] = None
50
- new: Optional[Any] = None
49
+ previous: Any | None = None
50
+ new: Any | None = None
51
51
 
52
52
  def __hash__(self) -> int:
53
53
  return hash(type(self))
@@ -57,12 +57,12 @@ class PropertyDiffElement(BaseDiffElement):
57
57
  branch: str
58
58
  type: str
59
59
  action: DiffAction
60
- path: Optional[str] = None
60
+ path: str | None = None
61
61
  db_id: str = Field(exclude=True)
62
62
  rel_id: str = Field(exclude=True)
63
- origin_rel_id: Optional[str] = Field(None, exclude=True)
64
- value: Optional[ValueElement] = None
65
- changed_at: Optional[Timestamp] = None
63
+ origin_rel_id: str | None = Field(None, exclude=True)
64
+ value: ValueElement | None = None
65
+ changed_at: Timestamp | None = None
66
66
 
67
67
 
68
68
  class NodeAttributeDiffElement(BaseDiffElement):
@@ -72,28 +72,28 @@ class NodeAttributeDiffElement(BaseDiffElement):
72
72
  action: DiffAction
73
73
  db_id: str = Field(exclude=True)
74
74
  rel_id: str = Field(exclude=True)
75
- origin_rel_id: Optional[str] = Field(None, exclude=True)
76
- changed_at: Optional[Timestamp] = None
75
+ origin_rel_id: str | None = Field(None, exclude=True)
76
+ changed_at: Timestamp | None = None
77
77
  properties: dict[str, PropertyDiffElement]
78
78
 
79
79
 
80
80
  class NodeDiffElement(BaseDiffElement):
81
- branch: Optional[str] = None
81
+ branch: str | None = None
82
82
  labels: list[str]
83
83
  kind: str
84
84
  id: str
85
85
  path: str
86
86
  action: DiffAction
87
87
  db_id: str = Field(exclude=True)
88
- rel_id: Optional[str] = Field(None, exclude=True)
89
- changed_at: Optional[Timestamp] = None
88
+ rel_id: str | None = Field(None, exclude=True)
89
+ changed_at: Timestamp | None = None
90
90
  attributes: dict[str, NodeAttributeDiffElement] = Field(default_factory=dict)
91
91
 
92
92
 
93
93
  class RelationshipEdgeNodeDiffElement(BaseDiffElement):
94
94
  id: str
95
- db_id: Optional[str] = Field(None, exclude=True)
96
- rel_id: Optional[str] = Field(None, exclude=True)
95
+ db_id: str | None = Field(None, exclude=True)
96
+ rel_id: str | None = Field(None, exclude=True)
97
97
  labels: list[str]
98
98
  kind: str
99
99
 
@@ -106,11 +106,11 @@ class RelationshipDiffElement(BaseDiffElement):
106
106
  action: DiffAction
107
107
  nodes: dict[str, RelationshipEdgeNodeDiffElement]
108
108
  properties: dict[str, PropertyDiffElement]
109
- changed_at: Optional[Timestamp] = None
109
+ changed_at: Timestamp | None = None
110
110
  paths: list[str]
111
111
  conflict_paths: list[str]
112
112
 
113
- def get_node_id_by_kind(self, kind: str) -> Optional[str]:
113
+ def get_node_id_by_kind(self, kind: str) -> str | None:
114
114
  ids = [rel.id for rel in self.nodes.values() if rel.kind == kind]
115
115
  if ids:
116
116
  return ids[0]
@@ -149,11 +149,11 @@ class ModifiedPath(BaseModel):
149
149
  node_id: str
150
150
  path_type: PathType
151
151
  kind: str
152
- element_name: Optional[str] = None
153
- property_name: Optional[str] = None
154
- peer_id: Optional[str] = None
152
+ element_name: str | None = None
153
+ property_name: str | None = None
154
+ peer_id: str | None = None
155
155
  action: DiffAction
156
- change: Optional[ValueElement] = None
156
+ change: ValueElement | None = None
157
157
 
158
158
  def __eq__(self, other: object) -> bool:
159
159
  if not isinstance(other, ModifiedPath):
@@ -248,7 +248,7 @@ class DataConflict(ObjectConflict):
248
248
  conflict_path: str
249
249
  path: str
250
250
  path_type: PathType
251
- property_name: Optional[str] = None
251
+ property_name: str | None = None
252
252
  change_type: str
253
253
  changes: list[BranchChanges] = Field(default_factory=list)
254
254
 
@@ -311,7 +311,7 @@ class BranchDiffFile(BaseModel):
311
311
  class BranchDiffRepository(BaseModel):
312
312
  branch: str
313
313
  id: str
314
- display_name: Optional[str] = None
314
+ display_name: str | None = None
315
315
  commit_from: str
316
316
  commit_to: str
317
317
  files: list[BranchDiffFile] = Field(default_factory=list)
@@ -325,14 +325,14 @@ class BranchDiffArtifactStorage(BaseModel):
325
325
  class ArtifactTarget(BaseModel):
326
326
  id: str
327
327
  kind: str
328
- display_label: Optional[str] = None
328
+ display_label: str | None = None
329
329
 
330
330
 
331
331
  class BranchDiffArtifact(BaseModel):
332
332
  branch: str
333
333
  id: str
334
- display_label: Optional[str] = None
334
+ display_label: str | None = None
335
335
  action: DiffAction
336
- target: Optional[ArtifactTarget] = None
337
- item_new: Optional[BranchDiffArtifactStorage] = None
338
- item_previous: Optional[BranchDiffArtifactStorage] = None
336
+ target: ArtifactTarget | None = None
337
+ item_new: BranchDiffArtifactStorage | None = None
338
+ item_previous: BranchDiffArtifactStorage | None = None
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from dataclasses import asdict, dataclass, field
4
4
  from enum import Enum
5
- from typing import TYPE_CHECKING, Any, Optional
5
+ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from infrahub.core.constants import (
8
8
  BranchSupportType,
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
20
20
  from neo4j.graph import Node as Neo4jNode
21
21
  from neo4j.graph import Path as Neo4jPath
22
22
  from neo4j.graph import Relationship as Neo4jRelationship
23
- from pendulum import Interval
23
+ from whenever import TimeDelta
24
24
 
25
25
  from infrahub.graphql.initialization import GraphqlContext
26
26
 
@@ -163,6 +163,10 @@ class EnrichedDiffAttribute(BaseSummary):
163
163
  def __hash__(self) -> int:
164
164
  return hash(self.name)
165
165
 
166
+ @property
167
+ def num_properties(self) -> int:
168
+ return len(self.properties)
169
+
166
170
  def get_all_conflicts(self) -> dict[str, EnrichedDiffConflict]:
167
171
  return {prop.path_identifier: prop.conflict for prop in self.properties if prop.conflict}
168
172
 
@@ -202,6 +206,10 @@ class EnrichedDiffSingleRelationship(BaseSummary):
202
206
  def __hash__(self) -> int:
203
207
  return hash(self.peer_id)
204
208
 
209
+ @property
210
+ def num_properties(self) -> int:
211
+ return len(self.properties)
212
+
205
213
  def get_all_conflicts(self) -> dict[str, EnrichedDiffConflict]:
206
214
  all_conflicts: dict[str, EnrichedDiffConflict] = {}
207
215
  if self.conflict:
@@ -248,6 +256,10 @@ class EnrichedDiffRelationship(BaseSummary):
248
256
  def __hash__(self) -> int:
249
257
  return hash(self.name)
250
258
 
259
+ @property
260
+ def num_properties(self) -> int:
261
+ return sum(r.num_properties for r in self.relationships)
262
+
251
263
  def get_all_conflicts(self) -> dict[str, EnrichedDiffConflict]:
252
264
  all_conflicts: dict[str, EnrichedDiffConflict] = {}
253
265
  for element in self.relationships:
@@ -308,6 +320,10 @@ class EnrichedDiffNode(BaseSummary):
308
320
  def __hash__(self) -> int:
309
321
  return hash(self.uuid)
310
322
 
323
+ @property
324
+ def num_properties(self) -> int:
325
+ return sum(a.num_properties for a in self.attributes) + sum(r.num_properties for r in self.relationships)
326
+
311
327
  def get_all_conflicts(self) -> dict[str, EnrichedDiffConflict]:
312
328
  all_conflicts: dict[str, EnrichedDiffConflict] = {}
313
329
  if self.conflict:
@@ -409,16 +425,16 @@ class EnrichedDiffRootMetadata(BaseSummary):
409
425
  from_time: Timestamp
410
426
  to_time: Timestamp
411
427
  uuid: str
412
- partner_uuid: str
413
428
  tracking_id: TrackingId
429
+ partner_uuid: str | None = field(default=None)
414
430
  exists_on_database: bool = field(default=False)
415
431
 
416
432
  def __hash__(self) -> int:
417
433
  return hash(self.uuid)
418
434
 
419
435
  @property
420
- def time_range(self) -> Interval:
421
- return self.to_time.obj - self.from_time.obj
436
+ def time_range(self) -> TimeDelta:
437
+ return self.to_time.get_obj() - self.from_time.get_obj()
422
438
 
423
439
  def update_metadata(
424
440
  self,
@@ -447,8 +463,8 @@ class EnrichedDiffRoot(EnrichedDiffRootMetadata):
447
463
  return hash(self.uuid)
448
464
 
449
465
  @property
450
- def time_range(self) -> Interval:
451
- return self.to_time.obj - self.from_time.obj
466
+ def time_range(self) -> TimeDelta:
467
+ return self.to_time.get_obj() - self.from_time.get_obj()
452
468
 
453
469
  def get_nodes_without_parents(self) -> set[EnrichedDiffNode]:
454
470
  nodes_with_parent_uuids = set()
@@ -470,6 +486,13 @@ class EnrichedDiffRoot(EnrichedDiffRootMetadata):
470
486
  except ValueError:
471
487
  return False
472
488
 
489
+ def get_node_map(self, node_uuids: set[str] | None = None) -> dict[str, EnrichedDiffNode]:
490
+ node_map = {}
491
+ for node in self.nodes:
492
+ if node_uuids is None or node.uuid in node_uuids:
493
+ node_map[node.uuid] = node
494
+ return node_map
495
+
473
496
  def get_all_conflicts(self) -> dict[str, EnrichedDiffConflict]:
474
497
  all_conflicts: dict[str, EnrichedDiffConflict] = {}
475
498
  for node in self.nodes:
@@ -825,13 +848,13 @@ class DatabasePath:
825
848
  return "Node" in self.property_node.labels
826
849
 
827
850
  @property
828
- def peer_id(self) -> Optional[str]:
851
+ def peer_id(self) -> str | None:
829
852
  if not self.property_is_peer:
830
853
  return None
831
854
  return str(self.property_node.get("uuid"))
832
855
 
833
856
  @property
834
- def peer_kind(self) -> Optional[str]:
857
+ def peer_kind(self) -> str | None:
835
858
  if not self.property_is_peer:
836
859
  return None
837
860
  return str(self.property_node.get("kind"))
@@ -0,0 +1,78 @@
1
+ from dataclasses import dataclass, field
2
+
3
+ from infrahub.core.constants import DiffAction, RelationshipCardinality
4
+
5
+ from .model.path import EnrichedDiffNode, EnrichedDiffRelationship, EnrichedDiffRoot
6
+
7
+
8
+ @dataclass
9
+ class ParentNodeAddRequest:
10
+ node_id: str
11
+ parent_id: str
12
+ parent_kind: str
13
+ parent_label: str
14
+ parent_rel_name: str
15
+ parent_rel_identifier: str
16
+ parent_rel_cardinality: RelationshipCardinality
17
+ parent_rel_label: str = field(default="")
18
+
19
+
20
+ class DiffParentNodeAdder:
21
+ def __init__(self) -> None:
22
+ self._diff_root: EnrichedDiffRoot | None = None
23
+ self._node_map: dict[str, EnrichedDiffNode] = {}
24
+
25
+ def initialize(self, enriched_diff_root: EnrichedDiffRoot) -> None:
26
+ self._diff_root = enriched_diff_root
27
+ self._node_map = enriched_diff_root.get_node_map()
28
+
29
+ def get_root(self) -> EnrichedDiffRoot:
30
+ if not self._diff_root:
31
+ raise RuntimeError("Must call initialize before using")
32
+ return self._diff_root
33
+
34
+ def get_node(self, node_uuid: str) -> EnrichedDiffNode:
35
+ return self._node_map[node_uuid]
36
+
37
+ def has_node(self, node_uuid: str) -> bool:
38
+ return node_uuid in self._node_map
39
+
40
+ def add_node(self, node: EnrichedDiffNode) -> None:
41
+ if node.uuid in self._node_map:
42
+ return
43
+ self._node_map[node.uuid] = node
44
+ self.get_root().nodes.add(node)
45
+
46
+ def add_parent(self, parent_request: ParentNodeAddRequest) -> EnrichedDiffNode:
47
+ if not self._diff_root:
48
+ raise RuntimeError("Must call initialize before using")
49
+ node = self.get_node(node_uuid=parent_request.node_id)
50
+ if not self.has_node(node_uuid=parent_request.parent_id):
51
+ parent = EnrichedDiffNode(
52
+ uuid=parent_request.parent_id,
53
+ kind=parent_request.parent_kind,
54
+ label=parent_request.parent_label,
55
+ action=DiffAction.UNCHANGED,
56
+ changed_at=None,
57
+ )
58
+ self.add_node(parent)
59
+ else:
60
+ parent = self.get_node(node_uuid=parent_request.parent_id)
61
+
62
+ try:
63
+ rel = node.get_relationship(name=parent_request.parent_rel_name)
64
+ rel.nodes.add(parent)
65
+ except ValueError:
66
+ node.relationships.add(
67
+ EnrichedDiffRelationship(
68
+ name=parent_request.parent_rel_name,
69
+ identifier=parent_request.parent_rel_identifier,
70
+ label=parent_request.parent_rel_label,
71
+ cardinality=parent_request.parent_rel_cardinality,
72
+ changed_at=None,
73
+ action=DiffAction.UNCHANGED,
74
+ nodes={parent},
75
+ )
76
+ )
77
+
78
+ return parent
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING
4
4
 
5
+ from infrahub import config
5
6
  from infrahub.core.manager import NodeManager
6
7
  from infrahub.core.registry import registry
7
8
  from infrahub.exceptions import SchemaNotFoundError
@@ -26,8 +27,18 @@ async def get_display_labels_per_kind(
26
27
  if skip_missing_schema:
27
28
  return {}
28
29
  raise
29
- nodes = await NodeManager.get_many(ids=ids, fields=fields, db=db, branch=branch)
30
- return {node_id: await node.render_display_label(db=db) for node_id, node in nodes.items()}
30
+ display_label_map: dict[str, str] = {}
31
+ offset = 0
32
+ limit = config.SETTINGS.database.query_size_limit
33
+ while True:
34
+ limited_ids = ids[offset : offset + limit]
35
+ if not limited_ids:
36
+ break
37
+ node_map = await NodeManager.get_many(ids=limited_ids, fields=fields, db=db, branch=branch)
38
+ for node_id, node in node_map.items():
39
+ display_label_map[node_id] = await node.render_display_label(db=db)
40
+ offset += limit
41
+ return display_label_map
31
42
 
32
43
 
33
44
  async def get_display_labels(nodes: dict[str, dict[str, list[str]]], db: InfrahubDatabase) -> dict[str, dict[str, str]]:
@@ -16,8 +16,8 @@ class IncExclFilterOptions(BaseModel):
16
16
 
17
17
 
18
18
  class IncExclActionFilterOptions(BaseModel):
19
- includes: set[DiffAction] = Field(default_factory=list)
20
- excludes: set[DiffAction] = Field(default_factory=list)
19
+ includes: set[DiffAction] = Field(default_factory=set)
20
+ excludes: set[DiffAction] = Field(default_factory=set)
21
21
 
22
22
  @property
23
23
  def is_empty(self) -> bool: