infrahub-server 1.2.0b1__py3-none-any.whl → 1.2.1__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 (297) 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 +1 -3
  5. infrahub/artifacts/tasks.py +1 -3
  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 +239 -11
  12. infrahub/computed_attribute/tasks.py +77 -442
  13. infrahub/computed_attribute/triggers.py +11 -45
  14. infrahub/config.py +43 -32
  15. infrahub/context.py +14 -0
  16. infrahub/core/account.py +4 -4
  17. infrahub/core/attribute.py +57 -57
  18. infrahub/core/branch/tasks.py +12 -9
  19. infrahub/core/changelog/diff.py +16 -8
  20. infrahub/core/changelog/models.py +189 -26
  21. infrahub/core/constants/__init__.py +5 -1
  22. infrahub/core/constants/infrahubkind.py +2 -0
  23. infrahub/core/constraint/node/runner.py +9 -8
  24. infrahub/core/diff/branch_differ.py +10 -10
  25. infrahub/core/diff/ipam_diff_parser.py +4 -5
  26. infrahub/core/diff/model/diff.py +27 -27
  27. infrahub/core/diff/model/path.py +3 -3
  28. infrahub/core/diff/query/merge.py +20 -17
  29. infrahub/core/diff/query_parser.py +4 -4
  30. infrahub/core/graph/__init__.py +1 -1
  31. infrahub/core/initialization.py +1 -10
  32. infrahub/core/ipam/constants.py +3 -4
  33. infrahub/core/ipam/reconciler.py +12 -12
  34. infrahub/core/ipam/utilization.py +10 -13
  35. infrahub/core/manager.py +34 -34
  36. infrahub/core/merge.py +7 -7
  37. infrahub/core/migrations/__init__.py +2 -3
  38. infrahub/core/migrations/graph/__init__.py +9 -4
  39. infrahub/core/migrations/graph/m017_add_core_profile.py +1 -5
  40. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +4 -4
  41. infrahub/core/migrations/graph/m020_duplicate_edges.py +160 -0
  42. infrahub/core/migrations/graph/m021_missing_hierarchy_merge.py +51 -0
  43. infrahub/core/migrations/graph/{m020_add_generate_template_attr.py → m022_add_generate_template_attr.py} +3 -3
  44. infrahub/core/migrations/graph/m023_deduplicate_cardinality_one_relationships.py +96 -0
  45. infrahub/core/migrations/query/attribute_add.py +2 -2
  46. infrahub/core/migrations/query/node_duplicate.py +18 -21
  47. infrahub/core/migrations/query/schema_attribute_update.py +2 -2
  48. infrahub/core/migrations/schema/models.py +19 -4
  49. infrahub/core/migrations/schema/tasks.py +2 -2
  50. infrahub/core/migrations/shared.py +16 -16
  51. infrahub/core/models.py +15 -6
  52. infrahub/core/node/__init__.py +29 -28
  53. infrahub/core/node/base.py +2 -4
  54. infrahub/core/node/constraints/attribute_uniqueness.py +2 -2
  55. infrahub/core/node/constraints/grouped_uniqueness.py +99 -47
  56. infrahub/core/node/constraints/interface.py +1 -2
  57. infrahub/core/node/delete_validator.py +3 -5
  58. infrahub/core/node/ipam.py +4 -4
  59. infrahub/core/node/permissions.py +7 -7
  60. infrahub/core/node/resource_manager/ip_address_pool.py +6 -6
  61. infrahub/core/node/resource_manager/ip_prefix_pool.py +6 -6
  62. infrahub/core/node/resource_manager/number_pool.py +3 -3
  63. infrahub/core/path.py +12 -12
  64. infrahub/core/property.py +11 -11
  65. infrahub/core/protocols.py +5 -0
  66. infrahub/core/protocols_base.py +21 -21
  67. infrahub/core/query/__init__.py +33 -33
  68. infrahub/core/query/attribute.py +6 -4
  69. infrahub/core/query/diff.py +3 -3
  70. infrahub/core/query/node.py +82 -32
  71. infrahub/core/query/relationship.py +24 -24
  72. infrahub/core/query/resource_manager.py +2 -0
  73. infrahub/core/query/standard_node.py +3 -3
  74. infrahub/core/query/subquery.py +9 -9
  75. infrahub/core/registry.py +13 -15
  76. infrahub/core/relationship/constraints/count.py +3 -4
  77. infrahub/core/relationship/constraints/peer_kind.py +3 -4
  78. infrahub/core/relationship/constraints/profiles_kind.py +2 -2
  79. infrahub/core/relationship/model.py +40 -46
  80. infrahub/core/schema/attribute_schema.py +9 -9
  81. infrahub/core/schema/basenode_schema.py +93 -44
  82. infrahub/core/schema/computed_attribute.py +3 -3
  83. infrahub/core/schema/definitions/core/__init__.py +13 -19
  84. infrahub/core/schema/definitions/core/account.py +151 -148
  85. infrahub/core/schema/definitions/core/artifact.py +122 -113
  86. infrahub/core/schema/definitions/core/builtin.py +19 -16
  87. infrahub/core/schema/definitions/core/check.py +61 -53
  88. infrahub/core/schema/definitions/core/core.py +17 -0
  89. infrahub/core/schema/definitions/core/generator.py +89 -85
  90. infrahub/core/schema/definitions/core/graphql_query.py +72 -70
  91. infrahub/core/schema/definitions/core/group.py +96 -93
  92. infrahub/core/schema/definitions/core/ipam.py +176 -235
  93. infrahub/core/schema/definitions/core/lineage.py +18 -16
  94. infrahub/core/schema/definitions/core/menu.py +42 -40
  95. infrahub/core/schema/definitions/core/permission.py +144 -142
  96. infrahub/core/schema/definitions/core/profile.py +16 -27
  97. infrahub/core/schema/definitions/core/propose_change.py +88 -79
  98. infrahub/core/schema/definitions/core/propose_change_comment.py +170 -165
  99. infrahub/core/schema/definitions/core/propose_change_validator.py +290 -288
  100. infrahub/core/schema/definitions/core/repository.py +231 -225
  101. infrahub/core/schema/definitions/core/resource_pool.py +156 -166
  102. infrahub/core/schema/definitions/core/template.py +27 -12
  103. infrahub/core/schema/definitions/core/transform.py +85 -76
  104. infrahub/core/schema/definitions/core/webhook.py +127 -101
  105. infrahub/core/schema/definitions/internal.py +16 -16
  106. infrahub/core/schema/dropdown.py +3 -4
  107. infrahub/core/schema/generated/attribute_schema.py +15 -18
  108. infrahub/core/schema/generated/base_node_schema.py +12 -14
  109. infrahub/core/schema/generated/node_schema.py +3 -5
  110. infrahub/core/schema/generated/relationship_schema.py +9 -11
  111. infrahub/core/schema/generic_schema.py +2 -2
  112. infrahub/core/schema/manager.py +20 -9
  113. infrahub/core/schema/node_schema.py +4 -2
  114. infrahub/core/schema/relationship_schema.py +7 -7
  115. infrahub/core/schema/schema_branch.py +276 -138
  116. infrahub/core/schema/schema_branch_computed.py +41 -4
  117. infrahub/core/task/task.py +3 -3
  118. infrahub/core/task/user_task.py +15 -15
  119. infrahub/core/utils.py +20 -18
  120. infrahub/core/validators/__init__.py +1 -3
  121. infrahub/core/validators/aggregated_checker.py +2 -2
  122. infrahub/core/validators/attribute/choices.py +2 -2
  123. infrahub/core/validators/attribute/enum.py +2 -2
  124. infrahub/core/validators/attribute/kind.py +2 -2
  125. infrahub/core/validators/attribute/length.py +2 -2
  126. infrahub/core/validators/attribute/optional.py +2 -2
  127. infrahub/core/validators/attribute/regex.py +2 -2
  128. infrahub/core/validators/attribute/unique.py +2 -2
  129. infrahub/core/validators/checks_runner.py +25 -2
  130. infrahub/core/validators/determiner.py +1 -3
  131. infrahub/core/validators/interface.py +6 -2
  132. infrahub/core/validators/model.py +22 -3
  133. infrahub/core/validators/models/validate_migration.py +17 -4
  134. infrahub/core/validators/node/attribute.py +2 -2
  135. infrahub/core/validators/node/generate_profile.py +2 -2
  136. infrahub/core/validators/node/hierarchy.py +3 -5
  137. infrahub/core/validators/node/inherit_from.py +27 -5
  138. infrahub/core/validators/node/relationship.py +2 -2
  139. infrahub/core/validators/relationship/count.py +4 -4
  140. infrahub/core/validators/relationship/optional.py +2 -2
  141. infrahub/core/validators/relationship/peer.py +2 -2
  142. infrahub/core/validators/shared.py +2 -2
  143. infrahub/core/validators/tasks.py +8 -0
  144. infrahub/core/validators/uniqueness/checker.py +22 -21
  145. infrahub/core/validators/uniqueness/index.py +2 -2
  146. infrahub/core/validators/uniqueness/model.py +11 -11
  147. infrahub/database/__init__.py +26 -22
  148. infrahub/database/metrics.py +7 -1
  149. infrahub/dependencies/builder/constraint/grouped/node_runner.py +1 -3
  150. infrahub/dependencies/component/registry.py +2 -2
  151. infrahub/events/__init__.py +25 -2
  152. infrahub/events/artifact_action.py +13 -25
  153. infrahub/events/branch_action.py +26 -18
  154. infrahub/events/generator.py +71 -0
  155. infrahub/events/group_action.py +10 -24
  156. infrahub/events/models.py +10 -16
  157. infrahub/events/node_action.py +87 -32
  158. infrahub/events/repository_action.py +5 -18
  159. infrahub/events/schema_action.py +4 -9
  160. infrahub/events/utils.py +16 -0
  161. infrahub/events/validator_action.py +55 -0
  162. infrahub/exceptions.py +23 -24
  163. infrahub/generators/models.py +1 -3
  164. infrahub/git/base.py +7 -7
  165. infrahub/git/integrator.py +26 -25
  166. infrahub/git/models.py +22 -9
  167. infrahub/git/repository.py +3 -3
  168. infrahub/git/tasks.py +67 -49
  169. infrahub/git/utils.py +48 -0
  170. infrahub/git/worktree.py +1 -2
  171. infrahub/git_credential/askpass.py +1 -2
  172. infrahub/graphql/analyzer.py +12 -0
  173. infrahub/graphql/app.py +13 -15
  174. infrahub/graphql/context.py +6 -0
  175. infrahub/graphql/initialization.py +3 -0
  176. infrahub/graphql/loaders/node.py +2 -12
  177. infrahub/graphql/loaders/peers.py +77 -0
  178. infrahub/graphql/loaders/shared.py +13 -0
  179. infrahub/graphql/manager.py +13 -10
  180. infrahub/graphql/mutations/artifact_definition.py +5 -5
  181. infrahub/graphql/mutations/computed_attribute.py +4 -5
  182. infrahub/graphql/mutations/graphql_query.py +5 -5
  183. infrahub/graphql/mutations/ipam.py +50 -70
  184. infrahub/graphql/mutations/main.py +164 -141
  185. infrahub/graphql/mutations/menu.py +5 -5
  186. infrahub/graphql/mutations/models.py +2 -4
  187. infrahub/graphql/mutations/node_getter/by_default_filter.py +10 -10
  188. infrahub/graphql/mutations/node_getter/by_hfid.py +1 -3
  189. infrahub/graphql/mutations/node_getter/by_id.py +1 -3
  190. infrahub/graphql/mutations/node_getter/interface.py +1 -2
  191. infrahub/graphql/mutations/proposed_change.py +7 -7
  192. infrahub/graphql/mutations/relationship.py +67 -35
  193. infrahub/graphql/mutations/repository.py +8 -8
  194. infrahub/graphql/mutations/resource_manager.py +3 -3
  195. infrahub/graphql/mutations/schema.py +4 -4
  196. infrahub/graphql/mutations/webhook.py +137 -0
  197. infrahub/graphql/parser.py +4 -4
  198. infrahub/graphql/queries/diff/tree.py +4 -4
  199. infrahub/graphql/queries/ipam.py +2 -2
  200. infrahub/graphql/queries/relationship.py +2 -2
  201. infrahub/graphql/queries/search.py +2 -2
  202. infrahub/graphql/resolvers/many_relationship.py +264 -0
  203. infrahub/graphql/resolvers/resolver.py +13 -110
  204. infrahub/graphql/subscription/graphql_query.py +2 -0
  205. infrahub/graphql/types/event.py +20 -11
  206. infrahub/graphql/types/node.py +2 -2
  207. infrahub/graphql/utils.py +2 -2
  208. infrahub/groups/ancestors.py +29 -0
  209. infrahub/groups/parsers.py +107 -0
  210. infrahub/menu/generator.py +7 -7
  211. infrahub/menu/menu.py +0 -10
  212. infrahub/menu/models.py +117 -16
  213. infrahub/menu/repository.py +111 -0
  214. infrahub/menu/utils.py +5 -8
  215. infrahub/message_bus/messages/__init__.py +1 -11
  216. infrahub/message_bus/messages/check_generator_run.py +2 -0
  217. infrahub/message_bus/messages/finalize_validator_execution.py +3 -0
  218. infrahub/message_bus/messages/request_generatordefinition_check.py +2 -0
  219. infrahub/message_bus/operations/__init__.py +0 -2
  220. infrahub/message_bus/operations/check/generator.py +1 -0
  221. infrahub/message_bus/operations/event/__init__.py +2 -2
  222. infrahub/message_bus/operations/finalize/validator.py +51 -1
  223. infrahub/message_bus/operations/requests/generator_definition.py +19 -19
  224. infrahub/message_bus/operations/requests/proposed_change.py +3 -1
  225. infrahub/pools/number.py +2 -4
  226. infrahub/proposed_change/tasks.py +37 -28
  227. infrahub/pytest_plugin.py +13 -10
  228. infrahub/server.py +1 -2
  229. infrahub/services/adapters/event/__init__.py +1 -1
  230. infrahub/task_manager/event.py +23 -9
  231. infrahub/tasks/artifact.py +2 -4
  232. infrahub/telemetry/__init__.py +0 -0
  233. infrahub/telemetry/constants.py +9 -0
  234. infrahub/telemetry/database.py +86 -0
  235. infrahub/telemetry/models.py +65 -0
  236. infrahub/telemetry/task_manager.py +77 -0
  237. infrahub/{tasks/telemetry.py → telemetry/tasks.py} +49 -56
  238. infrahub/telemetry/utils.py +11 -0
  239. infrahub/trace.py +4 -4
  240. infrahub/transformations/tasks.py +2 -2
  241. infrahub/trigger/catalogue.py +2 -5
  242. infrahub/trigger/constants.py +0 -8
  243. infrahub/trigger/models.py +14 -1
  244. infrahub/trigger/setup.py +90 -0
  245. infrahub/trigger/tasks.py +35 -90
  246. infrahub/utils.py +11 -1
  247. infrahub/validators/__init__.py +0 -0
  248. infrahub/validators/events.py +42 -0
  249. infrahub/validators/tasks.py +41 -0
  250. infrahub/webhook/gather.py +17 -0
  251. infrahub/webhook/models.py +22 -5
  252. infrahub/webhook/tasks.py +44 -19
  253. infrahub/webhook/triggers.py +22 -5
  254. infrahub/workers/infrahub_async.py +2 -2
  255. infrahub/workers/utils.py +2 -2
  256. infrahub/workflows/catalogue.py +28 -20
  257. infrahub/workflows/initialization.py +1 -3
  258. infrahub/workflows/models.py +1 -1
  259. infrahub/workflows/utils.py +10 -1
  260. infrahub_sdk/client.py +27 -8
  261. infrahub_sdk/config.py +3 -0
  262. infrahub_sdk/context.py +13 -0
  263. infrahub_sdk/exceptions.py +6 -0
  264. infrahub_sdk/generator.py +4 -1
  265. infrahub_sdk/graphql.py +45 -13
  266. infrahub_sdk/node.py +69 -20
  267. infrahub_sdk/protocols_base.py +32 -11
  268. infrahub_sdk/query_groups.py +6 -35
  269. infrahub_sdk/schema/__init__.py +55 -26
  270. infrahub_sdk/schema/main.py +8 -0
  271. infrahub_sdk/task/__init__.py +10 -0
  272. infrahub_sdk/task/manager.py +12 -6
  273. infrahub_sdk/testing/schemas/animal.py +9 -0
  274. infrahub_sdk/timestamp.py +12 -4
  275. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/METADATA +3 -2
  276. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/RECORD +289 -260
  277. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/entry_points.txt +1 -0
  278. infrahub_testcontainers/constants.py +2 -0
  279. infrahub_testcontainers/container.py +157 -12
  280. infrahub_testcontainers/docker-compose.test.yml +31 -6
  281. infrahub_testcontainers/helpers.py +18 -73
  282. infrahub_testcontainers/host.py +41 -0
  283. infrahub_testcontainers/measurements.py +93 -0
  284. infrahub_testcontainers/models.py +38 -0
  285. infrahub_testcontainers/performance_test.py +166 -0
  286. infrahub_testcontainers/plugin.py +136 -0
  287. infrahub_testcontainers/prometheus.yml +30 -0
  288. infrahub/message_bus/messages/event_branch_create.py +0 -11
  289. infrahub/message_bus/messages/event_branch_delete.py +0 -11
  290. infrahub/message_bus/messages/event_branch_rebased.py +0 -9
  291. infrahub/message_bus/messages/event_node_mutated.py +0 -15
  292. infrahub/message_bus/messages/event_schema_update.py +0 -9
  293. infrahub/message_bus/operations/event/node.py +0 -20
  294. infrahub/message_bus/operations/event/schema.py +0 -17
  295. infrahub/webhook/constants.py +0 -1
  296. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/LICENSE.txt +0 -0
  297. {infrahub_server-1.2.0b1.dist-info → infrahub_server-1.2.1.dist-info}/WHEEL +0 -0
infrahub/core/property.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Optional, Union
3
+ from typing import TYPE_CHECKING
4
4
  from uuid import UUID
5
5
 
6
6
  from pydantic import BaseModel
@@ -32,7 +32,7 @@ class FlagPropertyMixin:
32
32
  is_visible = True
33
33
  is_protected = False
34
34
 
35
- def _init_flag_property_mixin(self, kwargs: Optional[dict] = None) -> None:
35
+ def _init_flag_property_mixin(self, kwargs: dict | None = None) -> None:
36
36
  if not kwargs:
37
37
  return
38
38
 
@@ -47,7 +47,7 @@ class NodePropertyMixin:
47
47
  branch: Branch
48
48
  at: Timestamp
49
49
 
50
- def _init_node_property_mixin(self, kwargs: Optional[dict] = None) -> None:
50
+ def _init_node_property_mixin(self, kwargs: dict | None = None) -> None:
51
51
  for node in self._node_properties:
52
52
  setattr(self, f"_{node}", None)
53
53
  setattr(self, f"{node}_id", None)
@@ -66,7 +66,7 @@ class NodePropertyMixin:
66
66
  return self._get_node_property_from_cache(name="source")
67
67
 
68
68
  @source.setter
69
- def source(self, value: Union[str, Node, UUID]) -> None:
69
+ def source(self, value: str | Node | UUID) -> None:
70
70
  self._set_node_property(name="source", value=value)
71
71
 
72
72
  @property
@@ -74,25 +74,25 @@ class NodePropertyMixin:
74
74
  return self._get_node_property_from_cache(name="owner")
75
75
 
76
76
  @owner.setter
77
- def owner(self, value: Optional[Union[str, Node, UUID]]) -> None:
77
+ def owner(self, value: str | Node | UUID | None) -> None:
78
78
  self._set_node_property(name="owner", value=value)
79
79
 
80
80
  def clear_owner(self) -> None:
81
81
  self._set_node_property(name="owner", value=None)
82
82
 
83
- async def get_source(self, db: InfrahubDatabase) -> Optional[Node]:
83
+ async def get_source(self, db: InfrahubDatabase) -> Node | None:
84
84
  return await self._get_node_property(name="source", db=db)
85
85
 
86
86
  def clear_source(self) -> None:
87
87
  self._set_node_property(name="source", value=None)
88
88
 
89
- def set_source(self, value: Union[str, Node, UUID]) -> None:
89
+ def set_source(self, value: str | Node | UUID) -> None:
90
90
  self._set_node_property(name="source", value=value)
91
91
 
92
- async def get_owner(self, db: InfrahubDatabase) -> Optional[Node]:
92
+ async def get_owner(self, db: InfrahubDatabase) -> Node | None:
93
93
  return await self._get_node_property(name="owner", db=db)
94
94
 
95
- def set_owner(self, value: Union[str, Node, UUID]) -> None:
95
+ def set_owner(self, value: str | Node | UUID) -> None:
96
96
  self._set_node_property(name="owner", value=value)
97
97
 
98
98
  def _get_node_property_from_cache(self, name: str) -> Node:
@@ -107,7 +107,7 @@ class NodePropertyMixin:
107
107
 
108
108
  return item
109
109
 
110
- async def _get_node_property(self, db: InfrahubDatabase, name: str) -> Optional[Node]:
110
+ async def _get_node_property(self, db: InfrahubDatabase, name: str) -> Node | None:
111
111
  """Return the node attribute.
112
112
  If the node is already present in cache, serve from the cache
113
113
  If the node is not present, query it on the fly using the node_id
@@ -117,7 +117,7 @@ class NodePropertyMixin:
117
117
 
118
118
  return getattr(self, f"_{name}", None)
119
119
 
120
- def _set_node_property(self, name: str, value: Optional[Union[str, Node, UUID]]) -> None:
120
+ def _set_node_property(self, name: str, value: str | Node | UUID | None) -> None:
121
121
  """Set the value of the node_property.
122
122
  If the value is a string, we assume it's an ID and we'll save it to query it later (if needed)
123
123
  If the value is a Node, we save the node and we extract the ID
@@ -148,6 +148,10 @@ class CoreMenu(CoreNode):
148
148
  children: RelationshipManager
149
149
 
150
150
 
151
+ class CoreObjectComponentTemplate(CoreNode):
152
+ template_name: String
153
+
154
+
151
155
  class CoreObjectTemplate(CoreNode):
152
156
  template_name: String
153
157
 
@@ -199,6 +203,7 @@ class CoreWebhook(CoreNode):
199
203
  name: String
200
204
  event_type: Enum
201
205
  branch_scope: Dropdown
206
+ node_kind: StringOptional
202
207
  description: StringOptional
203
208
  url: URL
204
209
  validate_certificates: BooleanOptional
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Optional, Protocol, Union, runtime_checkable
3
+ from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
4
4
 
5
5
  from typing_extensions import Self
6
6
 
@@ -38,23 +38,23 @@ class InfrahubDatabase(Protocol):
38
38
  @property
39
39
  def is_transaction(self) -> bool: ...
40
40
 
41
- def add_schema(self, schema: SchemaBranch, name: Optional[str] = None) -> None: ...
42
- def start_session(self, read_only: bool = False, schemas: Optional[list[SchemaBranch]] = None) -> Self: ...
43
- def start_transaction(self, schemas: Optional[list[SchemaBranch]] = None) -> Self: ...
41
+ def add_schema(self, schema: SchemaBranch, name: str | None = None) -> None: ...
42
+ def start_session(self, read_only: bool = False, schemas: list[SchemaBranch] | None = None) -> Self: ...
43
+ def start_transaction(self, schemas: list[SchemaBranch] | None = None) -> Self: ...
44
44
  async def session(self) -> AsyncSession: ...
45
- async def transaction(self, name: Optional[str]) -> AsyncTransaction: ...
45
+ async def transaction(self, name: str | None) -> AsyncTransaction: ...
46
46
  async def close(self) -> None: ...
47
47
 
48
48
  async def execute_query(
49
- self, query: str, params: Optional[dict[str, Any]] = None, name: str = "undefined"
49
+ self, query: str, params: dict[str, Any] | None = None, name: str = "undefined"
50
50
  ) -> list[Record]: ...
51
51
 
52
52
  async def execute_query_with_metadata(
53
- self, query: str, params: Optional[dict[str, Any]] = None, name: str = "undefined"
53
+ self, query: str, params: dict[str, Any] | None = None, name: str = "undefined"
54
54
  ) -> tuple[list[Record], dict[str, Any]]: ...
55
55
 
56
56
  async def run_query(
57
- self, query: str, params: Optional[dict[str, Any]] = None, name: str = "undefined"
57
+ self, query: str, params: dict[str, Any] | None = None, name: str = "undefined"
58
58
  ) -> AsyncResult: ...
59
59
 
60
60
  def render_list_comprehension(self, items: str, item_name: str) -> str: ...
@@ -73,29 +73,29 @@ class CoreNode(Protocol):
73
73
  @classmethod
74
74
  async def init(
75
75
  cls,
76
- schema: Union[NodeSchema, ProfileSchema, str],
76
+ schema: NodeSchema | ProfileSchema | str,
77
77
  db: InfrahubDatabase,
78
- branch: Optional[Union[Branch, str]] = None,
79
- at: Optional[Union[Timestamp, str]] = None,
78
+ branch: Branch | str | None = None,
79
+ at: Timestamp | str | None = None,
80
80
  ) -> Self: ...
81
- async def new(self, db: InfrahubDatabase, id: Optional[str] = None, **kwargs: Any) -> Self: ...
82
- async def save(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> Self: ...
83
- async def delete(self, db: InfrahubDatabase, at: Optional[Timestamp] = None) -> None: ...
81
+ async def new(self, db: InfrahubDatabase, id: str | None = None, **kwargs: Any) -> Self: ...
82
+ async def save(self, db: InfrahubDatabase, at: Timestamp | None = None) -> Self: ...
83
+ async def delete(self, db: InfrahubDatabase, at: Timestamp | None = None) -> None: ...
84
84
  async def load(
85
85
  self,
86
86
  db: InfrahubDatabase,
87
- id: Optional[str] = None,
88
- db_id: Optional[str] = None,
89
- updated_at: Optional[Union[Timestamp, str]] = None,
87
+ id: str | None = None,
88
+ db_id: str | None = None,
89
+ updated_at: Timestamp | str | None = None,
90
90
  **kwargs: Any,
91
91
  ) -> Self: ...
92
92
  async def to_graphql(
93
93
  self,
94
94
  db: InfrahubDatabase,
95
- fields: Optional[dict] = None,
96
- related_node_ids: Optional[set] = None,
95
+ fields: dict | None = None,
96
+ related_node_ids: set | None = None,
97
97
  filter_sensitive: bool = False,
98
- permissions: Optional[dict] = None,
98
+ permissions: dict | None = None,
99
99
  ) -> dict: ...
100
- async def render_display_label(self, db: Optional[InfrahubDatabase] = None) -> str: ...
100
+ async def render_display_label(self, db: InfrahubDatabase | None = None) -> str: ...
101
101
  async def from_graphql(self, data: dict, db: InfrahubDatabase) -> bool: ...
@@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
4
4
  from collections import defaultdict
5
5
  from dataclasses import dataclass, field
6
6
  from enum import Enum
7
- from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator, Optional, TypeVar, Union
7
+ from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator, TypeVar
8
8
 
9
9
  import ujson
10
10
  from neo4j.graph import Node as Neo4jNode
@@ -68,9 +68,9 @@ class QueryRelDirection(Enum):
68
68
  @dataclass
69
69
  class QueryElement:
70
70
  type: QueryElementType
71
- name: Optional[str] = None
72
- labels: Optional[list[str]] = None
73
- params: Optional[dict] = None
71
+ name: str | None = None
72
+ labels: list[str] | None = None
73
+ params: dict | None = None
74
74
 
75
75
  def __str__(self) -> str:
76
76
  main_str = "%s%s%s" % (self.name or "", self.labels_as_str, self.params_as_str)
@@ -112,7 +112,7 @@ class QueryRel(QueryElement):
112
112
  type: QueryElementType = QueryElementType.RELATIONSHIP
113
113
  direction: QueryRelDirection = QueryRelDirection.BIDIR
114
114
  length_min: int = 1
115
- length_max: Optional[int] = None
115
+ length_max: int | None = None
116
116
 
117
117
  def __str__(self) -> str:
118
118
  length_str = ""
@@ -160,7 +160,7 @@ def cleanup_return_labels(labels: list[str]) -> list[str]:
160
160
 
161
161
 
162
162
  class QueryResult:
163
- def __init__(self, data: list[Union[Neo4jNode, Neo4jRelationship, list[Neo4jNode]]], labels: list[str]):
163
+ def __init__(self, data: list[Neo4jNode | Neo4jRelationship | list[Neo4jNode]], labels: list[str]):
164
164
  self.data = data
165
165
  self.labels = labels
166
166
  self.branch_score: int = 0
@@ -212,23 +212,23 @@ class QueryResult:
212
212
  self.has_deleted_rels = True
213
213
  return
214
214
 
215
- def _get(self, label: str) -> Union[Neo4jNode, Neo4jRelationship, list[Neo4jNode]]:
215
+ def _get(self, label: str) -> Neo4jNode | Neo4jRelationship | list[Neo4jNode]:
216
216
  if label not in self.labels:
217
217
  raise ValueError(f"{label} is not a valid value for this query, must be one of {self.labels}")
218
218
 
219
219
  return_id = self.labels.index(label)
220
220
  return self.data[return_id]
221
221
 
222
- def get(self, label: str) -> Union[Neo4jNode, Neo4jRelationship]:
222
+ def get(self, label: str) -> Neo4jNode | Neo4jRelationship:
223
223
  return self._get(label=label)
224
224
 
225
- def get_as_str(self, label: str) -> Optional[str]:
225
+ def get_as_str(self, label: str) -> str | None:
226
226
  item = self._get(label=label)
227
227
  if item:
228
228
  return str(item)
229
229
  return None
230
230
 
231
- def get_as_optional_type(self, label: str, return_type: Callable[..., RETURN_TYPE]) -> Optional[RETURN_TYPE]:
231
+ def get_as_optional_type(self, label: str, return_type: Callable[..., RETURN_TYPE]) -> RETURN_TYPE | None:
232
232
  """Return a label as a given type.
233
233
 
234
234
  For example if an integer is needed the caller would use:
@@ -305,7 +305,7 @@ class QueryResult:
305
305
  class QueryStats:
306
306
  stats: list[QueryStat] = field(default_factory=list)
307
307
 
308
- def add(self, data: Optional[dict[str, Any]]) -> None:
308
+ def add(self, data: dict[str, Any] | None) -> None:
309
309
  if data:
310
310
  self.stats.append(QueryStat.from_metadata(data))
311
311
 
@@ -322,13 +322,13 @@ class QueryStats:
322
322
  @dataclass
323
323
  class QueryStat:
324
324
  contains_updates: bool = False
325
- labels_added: Optional[int] = None
326
- labels_removed: Optional[int] = None
327
- nodes_created: Optional[int] = None
328
- nodes_deleted: Optional[int] = None
329
- properties_set: Optional[int] = None
330
- relationships_created: Optional[int] = None
331
- relationships_deleted: Optional[int] = None
325
+ labels_added: int | None = None
326
+ labels_removed: int | None = None
327
+ nodes_created: int | None = None
328
+ nodes_deleted: int | None = None
329
+ properties_set: int | None = None
330
+ relationships_created: int | None = None
331
+ relationships_deleted: int | None = None
332
332
 
333
333
  @classmethod
334
334
  def from_metadata(cls, data: dict[str, Any]) -> Self:
@@ -346,11 +346,11 @@ class Query(ABC):
346
346
 
347
347
  def __init__(
348
348
  self,
349
- branch: Optional[Branch] = None,
350
- at: Optional[Union[Timestamp, str]] = None,
351
- limit: Optional[int] = None,
352
- offset: Optional[int] = None,
353
- order_by: Optional[list[str]] = None,
349
+ branch: Branch | None = None,
350
+ at: Timestamp | str | None = None,
351
+ limit: int | None = None,
352
+ offset: int | None = None,
353
+ order_by: list[str] | None = None,
354
354
  branch_agnostic: bool = False,
355
355
  ):
356
356
  if branch:
@@ -379,7 +379,7 @@ class Query(ABC):
379
379
 
380
380
  self.stats: QueryStats = QueryStats()
381
381
 
382
- def update_return_labels(self, value: Union[str, list[str]]) -> None:
382
+ def update_return_labels(self, value: str | list[str]) -> None:
383
383
  if isinstance(value, str) and value not in self.return_labels:
384
384
  self.return_labels.append(value)
385
385
  return
@@ -391,10 +391,10 @@ class Query(ABC):
391
391
  async def init(
392
392
  cls,
393
393
  db: InfrahubDatabase,
394
- branch: Optional[Branch] = None,
395
- at: Optional[Union[Timestamp, str]] = None,
396
- limit: Optional[int] = None,
397
- offset: Optional[int] = None,
394
+ branch: Branch | None = None,
395
+ at: Timestamp | str | None = None,
396
+ limit: int | None = None,
397
+ offset: int | None = None,
398
398
  **kwargs: Any,
399
399
  ) -> Self:
400
400
  query = cls(branch=branch, at=at, limit=limit, offset=offset, **kwargs)
@@ -412,7 +412,7 @@ class Query(ABC):
412
412
  Right now it's mainly used to add more labels to the metrics."""
413
413
  return {}
414
414
 
415
- def add_to_query(self, query: Union[str, list[str]]) -> None:
415
+ def add_to_query(self, query: str | list[str]) -> None:
416
416
  """Add a new section at the end of the query.
417
417
 
418
418
  A string with multiple lines will be broken down into multiple entries in self.query_lines
@@ -424,7 +424,7 @@ class Query(ABC):
424
424
  else:
425
425
  self.query_lines.extend([line.strip() for line in query.split("\n") if line.strip()])
426
426
 
427
- def add_subquery(self, subquery: str, with_clause: Optional[str] = None) -> None:
427
+ def add_subquery(self, subquery: str, with_clause: str | None = None) -> None:
428
428
  self.add_to_query("CALL {")
429
429
  self.add_to_query(subquery)
430
430
  self.add_to_query("}")
@@ -435,8 +435,8 @@ class Query(ABC):
435
435
  self,
436
436
  var: bool = False,
437
437
  inline: bool = False,
438
- limit: Optional[int] = None,
439
- offset: Optional[int] = None,
438
+ limit: int | None = None,
439
+ offset: int | None = None,
440
440
  ) -> str:
441
441
  # Make a local copy of the _query_lines
442
442
  limit = limit or self.limit
@@ -602,7 +602,7 @@ class Query(ABC):
602
602
 
603
603
  return results[0][0]
604
604
 
605
- def get_result(self) -> Optional[QueryResult]:
605
+ def get_result(self) -> QueryResult | None:
606
606
  """Return a single Result."""
607
607
 
608
608
  if not self.has_been_executed:
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Optional, Union
3
+ from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from infrahub.core.constants import AttributeDBNodeType
6
6
  from infrahub.core.constants.relationship_label import RELATIONSHIP_TO_NODE_LABEL, RELATIONSHIP_TO_VALUE_LABEL
@@ -20,9 +20,9 @@ class AttributeQuery(Query):
20
20
  def __init__(
21
21
  self,
22
22
  attr: BaseAttribute,
23
- attr_id: Optional[str] = None,
24
- at: Optional[Union[Timestamp, str]] = None,
25
- branch: Optional[Branch] = None,
23
+ attr_id: str | None = None,
24
+ at: Timestamp | str | None = None,
25
+ branch: Branch | None = None,
26
26
  **kwargs: Any,
27
27
  ):
28
28
  self.attr = attr
@@ -66,6 +66,8 @@ class AttributeUpdateValueQuery(AttributeQuery):
66
66
  query = """
67
67
  MATCH (a:Attribute { uuid: $attr_uuid })
68
68
  MERGE (av:%(labels)s { %(props)s } )
69
+ WITH av, a
70
+ LIMIT 1
69
71
  CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "active", from: $at }]->(av)
70
72
  """ % {"rel_label": self.attr._rel_to_value_label, "labels": ":".join(labels), "props": ", ".join(prop_list)}
71
73
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Any, Union
3
+ from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from infrahub import config
6
6
  from infrahub.core.constants import GLOBAL_BRANCH_NAME, BranchSupportType
@@ -21,8 +21,8 @@ class DiffQuery(Query):
21
21
  def __init__(
22
22
  self,
23
23
  branch: Branch,
24
- diff_from: Union[Timestamp, str] = None,
25
- diff_to: Union[Timestamp, str] = None,
24
+ diff_from: Timestamp | str = None,
25
+ diff_to: Timestamp | str = None,
26
26
  **kwargs,
27
27
  ):
28
28
  """A diff is always in the context of a branch"""
@@ -5,7 +5,7 @@ from copy import copy
5
5
  from dataclasses import dataclass
6
6
  from dataclasses import field as dataclass_field
7
7
  from enum import Enum
8
- from typing import TYPE_CHECKING, Any, AsyncIterator, Generator, Optional, Union
8
+ from typing import TYPE_CHECKING, Any, AsyncIterator, Generator
9
9
 
10
10
  from infrahub import config
11
11
  from infrahub.core.constants import (
@@ -37,7 +37,7 @@ if TYPE_CHECKING:
37
37
 
38
38
  @dataclass
39
39
  class NodeToProcess:
40
- schema: Optional[Union[NodeSchema, ProfileSchema, TemplateSchema]]
40
+ schema: NodeSchema | ProfileSchema | TemplateSchema | None
41
41
 
42
42
  node_id: str
43
43
  node_uuid: str
@@ -65,7 +65,7 @@ class AttributeFromDB:
65
65
  attr_uuid: str
66
66
 
67
67
  attr_value_id: str
68
- attr_value_uuid: Optional[str]
68
+ attr_value_uuid: str | None
69
69
 
70
70
  value: Any
71
71
  content: Any
@@ -96,11 +96,11 @@ class PeerInfo:
96
96
  class NodeQuery(Query):
97
97
  def __init__(
98
98
  self,
99
- node: Optional[Node] = None,
100
- node_id: Optional[str] = None,
101
- node_db_id: Optional[int] = None,
102
- id: Optional[str] = None,
103
- branch: Optional[Branch] = None,
99
+ node: Node | None = None,
100
+ node_id: str | None = None,
101
+ node_db_id: int | None = None,
102
+ id: str | None = None,
103
+ branch: Branch | None = None,
104
104
  **kwargs,
105
105
  ) -> None:
106
106
  # TODO Validate that Node is a valid node
@@ -202,15 +202,16 @@ class NodeCreateAllQuery(NodeQuery):
202
202
  }
203
203
  ipnetwork_prop_list = [f"{key}: {value}" for key, value in ipnetwork_prop.items()]
204
204
 
205
- query = """
206
- MATCH (root:Root)
207
- CREATE (n:Node:%(labels)s $node_prop )
208
- CREATE (n)-[r:IS_PART_OF $node_branch_prop ]->(root)
205
+ attrs_query = """
209
206
  WITH distinct n
210
- FOREACH ( attr IN $attrs |
207
+ UNWIND $attrs AS attr
208
+ CALL {
209
+ WITH n, attr
211
210
  CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
212
211
  CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
213
212
  MERGE (av:AttributeValue { value: attr.content.value, is_default: attr.content.is_default })
213
+ WITH n, attr, av, a
214
+ LIMIT 1
214
215
  CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
215
216
  MERGE (ip:Boolean { value: attr.is_protected })
216
217
  MERGE (iv:Boolean { value: attr.is_visible })
@@ -224,11 +225,19 @@ class NodeCreateAllQuery(NodeQuery):
224
225
  MERGE (peer:Node { uuid: prop.peer_id })
225
226
  CREATE (a)-[:HAS_OWNER { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
226
227
  )
227
- )
228
- FOREACH ( attr IN $attrs_iphost |
228
+ }"""
229
+
230
+ attrs_iphost_query = """
231
+ WITH distinct n
232
+ UNWIND $attrs_iphost AS attr_iphost
233
+ CALL {
234
+ WITH n, attr_iphost
235
+ WITH n, attr_iphost AS attr
229
236
  CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
230
237
  CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
231
238
  MERGE (av:AttributeValue:AttributeIPHost { %(iphost_prop)s })
239
+ WITH n, attr, av, a
240
+ LIMIT 1
232
241
  CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
233
242
  MERGE (ip:Boolean { value: attr.is_protected })
234
243
  MERGE (iv:Boolean { value: attr.is_visible })
@@ -242,11 +251,20 @@ class NodeCreateAllQuery(NodeQuery):
242
251
  MERGE (peer:Node { uuid: prop.peer_id })
243
252
  CREATE (a)-[:HAS_OWNER { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
244
253
  )
245
- )
246
- FOREACH ( attr IN $attrs_ipnetwork |
254
+ }
255
+ """ % {"iphost_prop": ", ".join(iphost_prop_list)}
256
+
257
+ attrs_ipnetwork_query = """
258
+ WITH distinct n
259
+ UNWIND $attrs_ipnetwork AS attr_ipnetwork
260
+ CALL {
261
+ WITH n, attr_ipnetwork
262
+ WITH n, attr_ipnetwork AS attr
247
263
  CREATE (a:Attribute { uuid: attr.uuid, name: attr.name, branch_support: attr.branch_support })
248
264
  CREATE (n)-[:HAS_ATTRIBUTE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(a)
249
265
  MERGE (av:AttributeValue:AttributeIPNetwork { %(ipnetwork_prop)s })
266
+ WITH n, attr, av, a
267
+ LIMIT 1
250
268
  CREATE (a)-[:HAS_VALUE { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(av)
251
269
  MERGE (ip:Boolean { value: attr.is_protected })
252
270
  MERGE (iv:Boolean { value: attr.is_visible })
@@ -260,8 +278,14 @@ class NodeCreateAllQuery(NodeQuery):
260
278
  MERGE (peer:Node { uuid: prop.peer_id })
261
279
  CREATE (a)-[:HAS_OWNER { branch: attr.branch, branch_level: attr.branch_level, status: attr.status, from: $at }]->(peer)
262
280
  )
263
- )
264
- FOREACH ( rel IN $rels_bidir |
281
+ }
282
+ """ % {"ipnetwork_prop": ", ".join(ipnetwork_prop_list)}
283
+
284
+ rels_bidir_query = """
285
+ WITH distinct n
286
+ UNWIND $rels_bidir AS rel
287
+ CALL {
288
+ WITH n, rel
265
289
  MERGE (d:Node { uuid: rel.destination_id })
266
290
  CREATE (rl:Relationship { uuid: rel.uuid, name: rel.name, branch_support: rel.branch_support })
267
291
  CREATE (n)-[:IS_RELATED %(rel_prop)s ]->(rl)
@@ -278,8 +302,15 @@ class NodeCreateAllQuery(NodeQuery):
278
302
  MERGE (peer:Node { uuid: prop.peer_id })
279
303
  CREATE (rl)-[:HAS_OWNER { branch: rel.branch, branch_level: rel.branch_level, status: rel.status, from: $at }]->(peer)
280
304
  )
281
- )
282
- FOREACH ( rel IN $rels_out |
305
+ }
306
+ """ % {"rel_prop": rel_prop_str}
307
+
308
+ rels_out_query = """
309
+ WITH distinct n
310
+ UNWIND $rels_out AS rel_out
311
+ CALL {
312
+ WITH n, rel_out
313
+ WITH n, rel_out as rel
283
314
  MERGE (d:Node { uuid: rel.destination_id })
284
315
  CREATE (rl:Relationship { uuid: rel.uuid, name: rel.name, branch_support: rel.branch_support })
285
316
  CREATE (n)-[:IS_RELATED %(rel_prop)s ]->(rl)
@@ -296,8 +327,15 @@ class NodeCreateAllQuery(NodeQuery):
296
327
  MERGE (peer:Node { uuid: prop.peer_id })
297
328
  CREATE (rl)-[:HAS_OWNER { branch: rel.branch, branch_level: rel.branch_level, status: rel.status, from: $at }]->(peer)
298
329
  )
299
- )
300
- FOREACH ( rel IN $rels_in |
330
+ }
331
+ """ % {"rel_prop": rel_prop_str}
332
+
333
+ rels_in_query = """
334
+ WITH distinct n
335
+ UNWIND $rels_in AS rel_in
336
+ CALL {
337
+ WITH n, rel_in
338
+ WITH n, rel_in AS rel
301
339
  MERGE (d:Node { uuid: rel.destination_id })
302
340
  CREATE (rl:Relationship { uuid: rel.uuid, name: rel.name, branch_support: rel.branch_support })
303
341
  CREATE (n)<-[:IS_RELATED %(rel_prop)s ]-(rl)
@@ -314,14 +352,23 @@ class NodeCreateAllQuery(NodeQuery):
314
352
  MERGE (peer:Node { uuid: prop.peer_id })
315
353
  CREATE (rl)-[:HAS_OWNER { branch: rel.branch, branch_level: rel.branch_level, status: rel.status, from: $at }]->(peer)
316
354
  )
317
- )
355
+ }
356
+ """ % {"rel_prop": rel_prop_str}
357
+
358
+ query = f"""
359
+ MATCH (root:Root)
360
+ CREATE (n:Node:%(labels)s $node_prop )
361
+ CREATE (n)-[r:IS_PART_OF $node_branch_prop ]->(root)
362
+ {attrs_query if self.params["attrs"] else ""}
363
+ {attrs_iphost_query if self.params["attrs_iphost"] else ""}
364
+ {attrs_ipnetwork_query if self.params["attrs_ipnetwork"] else ""}
365
+ {rels_bidir_query if self.params["rels_bidir"] else ""}
366
+ {rels_out_query if self.params["rels_out"] else ""}
367
+ {rels_in_query if self.params["rels_in"] else ""}
318
368
  WITH distinct n
319
369
  MATCH (n)-[:HAS_ATTRIBUTE|IS_RELATED]-(rn)-[:HAS_VALUE|IS_RELATED]-(rv)
320
370
  """ % {
321
371
  "labels": ":".join(self.node.get_labels()),
322
- "rel_prop": rel_prop_str,
323
- "iphost_prop": ", ".join(iphost_prop_list),
324
- "ipnetwork_prop": ", ".join(ipnetwork_prop_list),
325
372
  }
326
373
 
327
374
  self.params["at"] = at.to_string()
@@ -415,7 +462,7 @@ class NodeListGetAttributeQuery(Query):
415
462
  def __init__(
416
463
  self,
417
464
  ids: list[str],
418
- fields: Optional[dict] = None,
465
+ fields: dict | None = None,
419
466
  include_source: bool = False,
420
467
  include_owner: bool = False,
421
468
  account=None,
@@ -618,18 +665,21 @@ class NodeListGetRelationshipsQuery(Query):
618
665
  MATCH paths_in = ((n)<-[r1:IS_RELATED]-(rel:Relationship)<-[r2:IS_RELATED]-(peer))
619
666
  WHERE ($relationship_identifiers IS NULL OR rel.name in $relationship_identifiers)
620
667
  AND all(r IN relationships(paths_in) WHERE (%(filters)s))
668
+ AND n.uuid <> peer.uuid
621
669
  RETURN n, rel, peer, r1, r2, "inbound" as direction
622
670
  UNION
623
671
  MATCH (n:Node) WHERE n.uuid IN $ids
624
672
  MATCH paths_out = ((n)-[r1:IS_RELATED]->(rel:Relationship)-[r2:IS_RELATED]->(peer))
625
673
  WHERE ($relationship_identifiers IS NULL OR rel.name in $relationship_identifiers)
626
674
  AND all(r IN relationships(paths_out) WHERE (%(filters)s))
675
+ AND n.uuid <> peer.uuid
627
676
  RETURN n, rel, peer, r1, r2, "outbound" as direction
628
677
  UNION
629
678
  MATCH (n:Node) WHERE n.uuid IN $ids
630
679
  MATCH paths_bidir = ((n)-[r1:IS_RELATED]->(rel:Relationship)<-[r2:IS_RELATED]-(peer))
631
680
  WHERE ($relationship_identifiers IS NULL OR rel.name in $relationship_identifiers)
632
681
  AND all(r IN relationships(paths_bidir) WHERE (%(filters)s))
682
+ AND n.uuid <> peer.uuid
633
683
  RETURN n, rel, peer, r1, r2, "bidirectional" as direction
634
684
  """ % {"filters": rels_filter}
635
685
 
@@ -757,7 +807,7 @@ class FieldAttributeRequirementType(Enum):
757
807
  @dataclass
758
808
  class FieldAttributeRequirement:
759
809
  field_name: str
760
- field: Optional[Union[AttributeSchema, RelationshipSchema]]
810
+ field: AttributeSchema | RelationshipSchema | None
761
811
  field_attr_name: str
762
812
  field_attr_value: Any
763
813
  index: int
@@ -817,7 +867,7 @@ class NodeGetListQuery(Query):
817
867
  def __init__(
818
868
  self,
819
869
  schema: NodeSchema,
820
- filters: Optional[dict] = None,
870
+ filters: dict | None = None,
821
871
  partial_match: bool = False,
822
872
  order: OrderModel | None = None,
823
873
  **kwargs: Any,
@@ -1264,8 +1314,8 @@ class NodeGetHierarchyQuery(Query):
1264
1314
  self,
1265
1315
  node_id: str,
1266
1316
  direction: RelationshipHierarchyDirection,
1267
- node_schema: Union[NodeSchema, GenericSchema],
1268
- filters: Optional[dict] = None,
1317
+ node_schema: NodeSchema | GenericSchema,
1318
+ filters: dict | None = None,
1269
1319
  hierarchical_ordering: bool = False,
1270
1320
  **kwargs: Any,
1271
1321
  ) -> None: