infrahub-server 1.4.13__py3-none-any.whl → 1.5.0__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 (222) hide show
  1. infrahub/actions/tasks.py +208 -16
  2. infrahub/api/artifact.py +3 -0
  3. infrahub/api/diff/diff.py +1 -1
  4. infrahub/api/internal.py +2 -0
  5. infrahub/api/query.py +2 -0
  6. infrahub/api/schema.py +27 -3
  7. infrahub/auth.py +5 -5
  8. infrahub/cli/__init__.py +2 -0
  9. infrahub/cli/db.py +160 -157
  10. infrahub/cli/dev.py +118 -0
  11. infrahub/cli/upgrade.py +56 -9
  12. infrahub/computed_attribute/tasks.py +19 -7
  13. infrahub/config.py +7 -2
  14. infrahub/core/attribute.py +35 -24
  15. infrahub/core/branch/enums.py +1 -1
  16. infrahub/core/branch/models.py +9 -5
  17. infrahub/core/branch/needs_rebase_status.py +11 -0
  18. infrahub/core/branch/tasks.py +72 -10
  19. infrahub/core/changelog/models.py +2 -10
  20. infrahub/core/constants/__init__.py +4 -0
  21. infrahub/core/constants/infrahubkind.py +1 -0
  22. infrahub/core/convert_object_type/object_conversion.py +201 -0
  23. infrahub/core/convert_object_type/repository_conversion.py +89 -0
  24. infrahub/core/convert_object_type/schema_mapping.py +27 -3
  25. infrahub/core/diff/model/path.py +4 -0
  26. infrahub/core/diff/payload_builder.py +1 -1
  27. infrahub/core/diff/query/artifact.py +1 -0
  28. infrahub/core/diff/query/field_summary.py +1 -0
  29. infrahub/core/graph/__init__.py +1 -1
  30. infrahub/core/initialization.py +7 -4
  31. infrahub/core/manager.py +3 -81
  32. infrahub/core/migrations/__init__.py +3 -0
  33. infrahub/core/migrations/exceptions.py +4 -0
  34. infrahub/core/migrations/graph/__init__.py +11 -10
  35. infrahub/core/migrations/graph/load_schema_branch.py +21 -0
  36. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +1 -1
  37. infrahub/core/migrations/graph/m037_index_attr_vals.py +11 -30
  38. infrahub/core/migrations/graph/m039_ipam_reconcile.py +9 -7
  39. infrahub/core/migrations/graph/m042_profile_attrs_in_db.py +147 -0
  40. infrahub/core/migrations/graph/m043_create_hfid_display_label_in_db.py +164 -0
  41. infrahub/core/migrations/graph/m044_backfill_hfid_display_label_in_db.py +864 -0
  42. infrahub/core/migrations/query/__init__.py +7 -8
  43. infrahub/core/migrations/query/attribute_add.py +8 -6
  44. infrahub/core/migrations/query/attribute_remove.py +134 -0
  45. infrahub/core/migrations/runner.py +54 -0
  46. infrahub/core/migrations/schema/attribute_kind_update.py +9 -3
  47. infrahub/core/migrations/schema/attribute_supports_profile.py +90 -0
  48. infrahub/core/migrations/schema/node_attribute_add.py +26 -5
  49. infrahub/core/migrations/schema/node_attribute_remove.py +13 -109
  50. infrahub/core/migrations/schema/node_kind_update.py +2 -1
  51. infrahub/core/migrations/schema/node_remove.py +2 -1
  52. infrahub/core/migrations/schema/placeholder_dummy.py +3 -2
  53. infrahub/core/migrations/shared.py +66 -19
  54. infrahub/core/models.py +2 -2
  55. infrahub/core/node/__init__.py +207 -54
  56. infrahub/core/node/create.py +53 -49
  57. infrahub/core/node/lock_utils.py +124 -0
  58. infrahub/core/node/node_property_attribute.py +230 -0
  59. infrahub/core/node/resource_manager/ip_address_pool.py +2 -1
  60. infrahub/core/node/resource_manager/ip_prefix_pool.py +2 -1
  61. infrahub/core/node/resource_manager/number_pool.py +2 -1
  62. infrahub/core/node/standard.py +1 -1
  63. infrahub/core/property.py +11 -0
  64. infrahub/core/protocols.py +8 -1
  65. infrahub/core/query/attribute.py +82 -15
  66. infrahub/core/query/ipam.py +16 -4
  67. infrahub/core/query/node.py +66 -188
  68. infrahub/core/query/relationship.py +44 -26
  69. infrahub/core/query/subquery.py +0 -8
  70. infrahub/core/relationship/model.py +69 -24
  71. infrahub/core/schema/__init__.py +56 -0
  72. infrahub/core/schema/attribute_schema.py +4 -2
  73. infrahub/core/schema/basenode_schema.py +42 -2
  74. infrahub/core/schema/definitions/core/__init__.py +2 -0
  75. infrahub/core/schema/definitions/core/check.py +1 -1
  76. infrahub/core/schema/definitions/core/generator.py +2 -0
  77. infrahub/core/schema/definitions/core/group.py +16 -2
  78. infrahub/core/schema/definitions/core/repository.py +7 -0
  79. infrahub/core/schema/definitions/core/transform.py +1 -1
  80. infrahub/core/schema/definitions/internal.py +12 -3
  81. infrahub/core/schema/generated/attribute_schema.py +2 -2
  82. infrahub/core/schema/generated/base_node_schema.py +6 -1
  83. infrahub/core/schema/manager.py +3 -0
  84. infrahub/core/schema/node_schema.py +1 -0
  85. infrahub/core/schema/relationship_schema.py +0 -1
  86. infrahub/core/schema/schema_branch.py +295 -10
  87. infrahub/core/schema/schema_branch_display.py +135 -0
  88. infrahub/core/schema/schema_branch_hfid.py +120 -0
  89. infrahub/core/validators/aggregated_checker.py +1 -1
  90. infrahub/database/graph.py +21 -0
  91. infrahub/display_labels/__init__.py +0 -0
  92. infrahub/display_labels/gather.py +48 -0
  93. infrahub/display_labels/models.py +240 -0
  94. infrahub/display_labels/tasks.py +192 -0
  95. infrahub/display_labels/triggers.py +22 -0
  96. infrahub/events/branch_action.py +27 -1
  97. infrahub/events/group_action.py +1 -1
  98. infrahub/events/node_action.py +1 -1
  99. infrahub/generators/constants.py +7 -0
  100. infrahub/generators/models.py +38 -12
  101. infrahub/generators/tasks.py +34 -16
  102. infrahub/git/base.py +38 -1
  103. infrahub/git/integrator.py +22 -14
  104. infrahub/graphql/api/dependencies.py +2 -4
  105. infrahub/graphql/api/endpoints.py +16 -6
  106. infrahub/graphql/app.py +2 -4
  107. infrahub/graphql/initialization.py +2 -3
  108. infrahub/graphql/manager.py +213 -137
  109. infrahub/graphql/middleware.py +12 -0
  110. infrahub/graphql/mutations/branch.py +16 -0
  111. infrahub/graphql/mutations/computed_attribute.py +110 -3
  112. infrahub/graphql/mutations/convert_object_type.py +44 -13
  113. infrahub/graphql/mutations/display_label.py +118 -0
  114. infrahub/graphql/mutations/generator.py +25 -7
  115. infrahub/graphql/mutations/hfid.py +125 -0
  116. infrahub/graphql/mutations/ipam.py +73 -41
  117. infrahub/graphql/mutations/main.py +61 -178
  118. infrahub/graphql/mutations/profile.py +195 -0
  119. infrahub/graphql/mutations/proposed_change.py +8 -1
  120. infrahub/graphql/mutations/relationship.py +2 -2
  121. infrahub/graphql/mutations/repository.py +22 -83
  122. infrahub/graphql/mutations/resource_manager.py +2 -2
  123. infrahub/graphql/mutations/webhook.py +1 -1
  124. infrahub/graphql/queries/resource_manager.py +1 -1
  125. infrahub/graphql/registry.py +173 -0
  126. infrahub/graphql/resolvers/resolver.py +2 -0
  127. infrahub/graphql/schema.py +8 -1
  128. infrahub/graphql/schema_sort.py +170 -0
  129. infrahub/graphql/types/branch.py +4 -1
  130. infrahub/graphql/types/enums.py +3 -0
  131. infrahub/groups/tasks.py +1 -1
  132. infrahub/hfid/__init__.py +0 -0
  133. infrahub/hfid/gather.py +48 -0
  134. infrahub/hfid/models.py +240 -0
  135. infrahub/hfid/tasks.py +191 -0
  136. infrahub/hfid/triggers.py +22 -0
  137. infrahub/lock.py +119 -42
  138. infrahub/locks/__init__.py +0 -0
  139. infrahub/locks/tasks.py +37 -0
  140. infrahub/patch/plan_writer.py +2 -2
  141. infrahub/permissions/constants.py +2 -0
  142. infrahub/profiles/__init__.py +0 -0
  143. infrahub/profiles/node_applier.py +101 -0
  144. infrahub/profiles/queries/__init__.py +0 -0
  145. infrahub/profiles/queries/get_profile_data.py +98 -0
  146. infrahub/profiles/tasks.py +63 -0
  147. infrahub/proposed_change/tasks.py +24 -5
  148. infrahub/repositories/__init__.py +0 -0
  149. infrahub/repositories/create_repository.py +113 -0
  150. infrahub/server.py +9 -1
  151. infrahub/services/__init__.py +8 -5
  152. infrahub/services/adapters/workflow/worker.py +5 -2
  153. infrahub/task_manager/event.py +5 -0
  154. infrahub/task_manager/models.py +7 -0
  155. infrahub/tasks/registry.py +6 -4
  156. infrahub/trigger/catalogue.py +4 -0
  157. infrahub/trigger/models.py +2 -0
  158. infrahub/trigger/setup.py +13 -4
  159. infrahub/trigger/tasks.py +6 -0
  160. infrahub/webhook/models.py +1 -1
  161. infrahub/workers/dependencies.py +3 -1
  162. infrahub/workers/infrahub_async.py +5 -1
  163. infrahub/workflows/catalogue.py +118 -3
  164. infrahub/workflows/initialization.py +21 -0
  165. infrahub/workflows/models.py +17 -2
  166. infrahub_sdk/branch.py +17 -8
  167. infrahub_sdk/checks.py +1 -1
  168. infrahub_sdk/client.py +376 -95
  169. infrahub_sdk/config.py +29 -2
  170. infrahub_sdk/convert_object_type.py +61 -0
  171. infrahub_sdk/ctl/branch.py +3 -0
  172. infrahub_sdk/ctl/check.py +2 -3
  173. infrahub_sdk/ctl/cli_commands.py +20 -12
  174. infrahub_sdk/ctl/config.py +8 -2
  175. infrahub_sdk/ctl/generator.py +6 -3
  176. infrahub_sdk/ctl/graphql.py +184 -0
  177. infrahub_sdk/ctl/repository.py +39 -1
  178. infrahub_sdk/ctl/schema.py +40 -10
  179. infrahub_sdk/ctl/task.py +110 -0
  180. infrahub_sdk/ctl/utils.py +4 -0
  181. infrahub_sdk/ctl/validate.py +5 -3
  182. infrahub_sdk/diff.py +4 -5
  183. infrahub_sdk/exceptions.py +2 -0
  184. infrahub_sdk/generator.py +7 -1
  185. infrahub_sdk/graphql/__init__.py +12 -0
  186. infrahub_sdk/graphql/constants.py +1 -0
  187. infrahub_sdk/graphql/plugin.py +85 -0
  188. infrahub_sdk/graphql/query.py +77 -0
  189. infrahub_sdk/{graphql.py → graphql/renderers.py} +88 -75
  190. infrahub_sdk/graphql/utils.py +40 -0
  191. infrahub_sdk/node/attribute.py +2 -0
  192. infrahub_sdk/node/node.py +28 -20
  193. infrahub_sdk/node/relationship.py +1 -3
  194. infrahub_sdk/playback.py +1 -2
  195. infrahub_sdk/protocols.py +54 -6
  196. infrahub_sdk/pytest_plugin/plugin.py +7 -4
  197. infrahub_sdk/pytest_plugin/utils.py +40 -0
  198. infrahub_sdk/repository.py +1 -2
  199. infrahub_sdk/schema/__init__.py +70 -4
  200. infrahub_sdk/schema/main.py +1 -0
  201. infrahub_sdk/schema/repository.py +8 -0
  202. infrahub_sdk/spec/models.py +7 -0
  203. infrahub_sdk/spec/object.py +54 -6
  204. infrahub_sdk/spec/processors/__init__.py +0 -0
  205. infrahub_sdk/spec/processors/data_processor.py +10 -0
  206. infrahub_sdk/spec/processors/factory.py +34 -0
  207. infrahub_sdk/spec/processors/range_expand_processor.py +56 -0
  208. infrahub_sdk/spec/range_expansion.py +118 -0
  209. infrahub_sdk/task/models.py +6 -4
  210. infrahub_sdk/timestamp.py +18 -6
  211. infrahub_sdk/transforms.py +1 -1
  212. {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/METADATA +9 -10
  213. {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/RECORD +221 -165
  214. infrahub_testcontainers/container.py +114 -2
  215. infrahub_testcontainers/docker-compose-cluster.test.yml +5 -0
  216. infrahub_testcontainers/docker-compose.test.yml +5 -0
  217. infrahub_testcontainers/models.py +2 -2
  218. infrahub_testcontainers/performance_test.py +4 -4
  219. infrahub/core/convert_object_type/conversion.py +0 -134
  220. {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/LICENSE.txt +0 -0
  221. {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/WHEEL +0 -0
  222. {infrahub_server-1.4.13.dist-info → infrahub_server-1.5.0.dist-info}/entry_points.txt +0 -0
@@ -133,7 +133,7 @@ class AttributeUpdateNodePropertyQuery(AttributeQuery):
133
133
  def __init__(
134
134
  self,
135
135
  prop_name: str,
136
- prop_id: str,
136
+ prop_id: str | None = None,
137
137
  **kwargs: Any,
138
138
  ):
139
139
  self.prop_name = prop_name
@@ -144,6 +144,8 @@ class AttributeUpdateNodePropertyQuery(AttributeQuery):
144
144
  async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
145
145
  at = self.at or self.attr.at
146
146
 
147
+ branch_filter, branch_params = self.branch.get_query_filter_path(at=at)
148
+ self.params.update(branch_params)
147
149
  self.params["attr_uuid"] = self.attr.id
148
150
  self.params["branch"] = self.branch.name
149
151
  self.params["branch_level"] = self.branch.hierarchy_level
@@ -151,21 +153,92 @@ class AttributeUpdateNodePropertyQuery(AttributeQuery):
151
153
  self.params["prop_name"] = self.prop_name
152
154
  self.params["prop_id"] = self.prop_id
153
155
 
154
- rel_name = f"HAS_{self.prop_name.upper()}"
156
+ rel_label = f"HAS_{self.prop_name.upper()}"
155
157
 
156
- query = (
158
+ if self.branch.is_default or self.branch.is_global:
159
+ node_query = """
160
+ MATCH (np:Node { uuid: $prop_id })-[r:IS_PART_OF]->(:Root)
161
+ WHERE r.branch IN $branch0
162
+ AND r.status = "active"
163
+ AND r.from <= $at AND (r.to IS NULL OR r.to > $at)
164
+ WITH np
165
+ LIMIT 1
157
166
  """
167
+ else:
168
+ node_query = """
169
+ MATCH (np:Node { uuid: $prop_id })-[r:IS_PART_OF]->(:Root)
170
+ WHERE %(branch_filter)s
171
+ ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
172
+ LIMIT 1
173
+ WITH np
174
+ WHERE r.status = "active"
175
+ """ % {"branch_filter": branch_filter}
176
+ self.add_to_query(node_query)
177
+
178
+ attr_query = """
158
179
  MATCH (a:Attribute { uuid: $attr_uuid })
159
- MATCH (np:Node { uuid: $prop_id })
160
- CREATE (a)-[r:%s { branch: $branch, branch_level: $branch_level, status: "active", from: $at }]->(np)
161
- """
162
- % rel_name
163
- )
180
+ CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "active", from: $at }]->(np)
181
+ """ % {"rel_label": rel_label}
182
+ self.add_to_query(attr_query)
164
183
 
165
- self.add_to_query(query)
166
184
  self.return_labels = ["a", "np", "r"]
167
185
 
168
186
 
187
+ class AttributeClearNodePropertyQuery(AttributeQuery):
188
+ name = "attribute_clear_node_property"
189
+ type: QueryType = QueryType.WRITE
190
+ insert_return: bool = False
191
+
192
+ def __init__(
193
+ self,
194
+ prop_name: str,
195
+ prop_id: str | None = None,
196
+ **kwargs: Any,
197
+ ):
198
+ self.prop_name = prop_name
199
+ self.prop_id = prop_id
200
+
201
+ super().__init__(**kwargs)
202
+
203
+ async def query_init(self, db: InfrahubDatabase, **kwargs: dict[str, Any]) -> None: # noqa: ARG002
204
+ at = self.at or self.attr.at
205
+
206
+ branch_filter, branch_params = self.branch.get_query_filter_path(at=at)
207
+ self.params.update(branch_params)
208
+ self.params["attr_uuid"] = self.attr.id
209
+ self.params["branch"] = self.branch.name
210
+ self.params["branch_level"] = self.branch.hierarchy_level
211
+ self.params["at"] = at.to_string()
212
+ self.params["prop_name"] = self.prop_name
213
+ self.params["prop_id"] = self.prop_id
214
+
215
+ rel_label = f"HAS_{self.prop_name.upper()}"
216
+ query = """
217
+ MATCH (a:Attribute { uuid: $attr_uuid })-[r:%(rel_label)s]->(np:Node { uuid: $prop_id })
218
+ WITH DISTINCT a, np
219
+ CALL (a, np) {
220
+ MATCH (a)-[r:%(rel_label)s]->(np)
221
+ WHERE %(branch_filter)s
222
+ ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
223
+ LIMIT 1
224
+ RETURN r AS property_edge
225
+ }
226
+ WITH a, np, property_edge
227
+ WHERE property_edge.status = "active"
228
+ CALL (property_edge) {
229
+ WITH property_edge
230
+ WHERE property_edge.branch = $branch
231
+ SET property_edge.to = $at
232
+ }
233
+ CALL (a, np, property_edge) {
234
+ WITH property_edge
235
+ WHERE property_edge.branch_level < $branch_level
236
+ CREATE (a)-[r:%(rel_label)s { branch: $branch, branch_level: $branch_level, status: "deleted", from: $at }]->(np)
237
+ }
238
+ """ % {"branch_filter": branch_filter, "rel_label": rel_label}
239
+ self.add_to_query(query)
240
+
241
+
169
242
  class AttributeGetQuery(AttributeQuery):
170
243
  name = "attribute_get"
171
244
  type: QueryType = QueryType.READ
@@ -204,7 +277,6 @@ async def default_attribute_query_filter(
204
277
  param_prefix: str | None = None,
205
278
  db: InfrahubDatabase | None = None, # noqa: ARG001
206
279
  partial_match: bool = False,
207
- support_profiles: bool = False,
208
280
  ) -> tuple[list[QueryElement], dict[str, Any], list[str]]:
209
281
  """Generate Query String Snippet to filter the right node."""
210
282
  attribute_value_label = GraphAttributeValueNode.get_default_label()
@@ -251,9 +323,6 @@ async def default_attribute_query_filter(
251
323
  query_where.append(f"toString(av.{filter_name}) =~ ${param_prefix}_{filter_name}")
252
324
  elif filter_name == "isnull":
253
325
  query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
254
- elif support_profiles:
255
- query_filter.append(QueryNode(name="av", labels=[attribute_value_label]))
256
- query_where.append(f"(av.{filter_name} = ${param_prefix}_{filter_name} OR av.is_default)")
257
326
  else:
258
327
  query_filter.append(
259
328
  QueryNode(
@@ -271,8 +340,6 @@ async def default_attribute_query_filter(
271
340
  if attribute_kind and attribute_kind == "List":
272
341
  query_params[f"{param_prefix}_{filter_name}"] = build_regex_attrs(values=filter_value)
273
342
  query_where.append(f"toString(av.value) =~ ${param_prefix}_{filter_name}")
274
- elif support_profiles:
275
- query_where.append(f"(av.value IN ${param_prefix}_value OR av.is_default)")
276
343
  else:
277
344
  query_where.append(f"av.value IN ${param_prefix}_value")
278
345
  query_params[f"{param_prefix}_value"] = filter_value
@@ -450,12 +450,23 @@ class IPPrefixReconcileQuery(Query):
450
450
  // ------------------
451
451
  CALL (ip_node) {
452
452
  OPTIONAL MATCH parent_prefix_path = (ip_node)-[r1:IS_RELATED]->(:Relationship {name: "parent__child"})-[r2:IS_RELATED]->(current_parent:%(ip_prefix_kind)s)
453
- WHERE all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
453
+ WHERE $is_prefix = TRUE
454
+ AND all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
454
455
  RETURN current_parent, (r1.status = "active" AND r2.status = "active") AS parent_is_active
455
456
  ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
456
457
  LIMIT 1
457
458
  }
458
- WITH ip_namespace, ip_node, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as current_parent
459
+ WITH ip_namespace, ip_node, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as prefix_parent
460
+ CALL (ip_node) {
461
+ OPTIONAL MATCH parent_prefix_path = (ip_node)-[r1:IS_RELATED]->(:Relationship {name: "ip_prefix__ip_address"})<-[r2:IS_RELATED]-(current_parent:%(ip_prefix_kind)s)
462
+ WHERE $is_prefix = FALSE
463
+ AND all(r IN relationships(parent_prefix_path) WHERE (%(branch_filter)s))
464
+ RETURN current_parent, (r1.status = "active" AND r2.status = "active") AS parent_is_active
465
+ ORDER BY r1.branch_level DESC, r1.from DESC, r1.status ASC, r2.branch_level DESC, r2.from DESC, r2.status ASC
466
+ LIMIT 1
467
+ }
468
+ WITH ip_namespace, ip_node, prefix_parent, CASE WHEN parent_is_active THEN current_parent ELSE NULL END as address_parent
469
+ WITH ip_namespace, ip_node, COALESCE(prefix_parent, address_parent) AS current_parent
459
470
  """ % {
460
471
  "branch_filter": branch_filter,
461
472
  "ip_prefix_kind": InfrahubKind.IPPREFIX,
@@ -467,7 +478,7 @@ class IPPrefixReconcileQuery(Query):
467
478
  // Get prefix node's current prefix children, if any exist
468
479
  // ------------------
469
480
  CALL (ip_node) {
470
- OPTIONAL MATCH child_prefix_path = (ip_node)<-[r1:IS_RELATED]-(:Relationship {name: "parent__child"})<-[r2:IS_RELATED]-(current_prefix_child:%(ip_prefix_kind)s)
481
+ OPTIONAL MATCH child_prefix_path = (ip_node:%(ip_prefix_kind)s)<-[r1:IS_RELATED]-(:Relationship {name: "parent__child"})<-[r2:IS_RELATED]-(current_prefix_child:%(ip_prefix_kind)s)
471
482
  WHERE all(r IN relationships(child_prefix_path) WHERE (%(branch_filter)s))
472
483
  WITH current_prefix_child, (r1.status = "active" AND r2.status = "active") AS is_active
473
484
  ORDER BY current_prefix_child.uuid, r1.branch_level DESC, r1.from DESC, r2.branch_level DESC, r2.from DESC
@@ -479,7 +490,7 @@ class IPPrefixReconcileQuery(Query):
479
490
  // Get prefix node's current address children, if any exist
480
491
  // ------------------
481
492
  CALL (ip_node) {
482
- OPTIONAL MATCH child_address_path = (ip_node)-[r1:IS_RELATED]-(:Relationship {name: "ip_prefix__ip_address"})-[r2:IS_RELATED]-(current_address_child:%(ip_address_kind)s)
493
+ OPTIONAL MATCH child_address_path = (ip_node:%(ip_prefix_kind)s)-[r1:IS_RELATED]->(:Relationship {name: "ip_prefix__ip_address"})<-[r2:IS_RELATED]-(current_address_child:%(ip_address_kind)s)
483
494
  WHERE all(r IN relationships(child_address_path) WHERE (%(branch_filter)s))
484
495
  WITH current_address_child, (r1.status = "active" AND r2.status = "active") AS is_active
485
496
  ORDER BY current_address_child.uuid, r1.branch_level DESC, r1.from DESC, r2.branch_level DESC, r2.from DESC
@@ -688,6 +699,7 @@ class IPPrefixReconcileQuery(Query):
688
699
  "ip_address_attribute_kind": ADDRESS_ATTRIBUTE_LABEL,
689
700
  }
690
701
  self.add_to_query(get_new_children_query)
702
+ self.order_by = ["ip_node.uuid"]
691
703
  self.return_labels = ["ip_node", "current_parent", "current_children", "new_parent", "new_children"]
692
704
 
693
705
  def _get_uuid_from_query(self, node_name: str) -> str | None:
@@ -11,6 +11,7 @@ from infrahub import config
11
11
  from infrahub.core import registry
12
12
  from infrahub.core.constants import (
13
13
  GLOBAL_BRANCH_NAME,
14
+ PROFILE_NODE_RELATIONSHIP_IDENTIFIER,
14
15
  AttributeDBNodeType,
15
16
  RelationshipDirection,
16
17
  RelationshipHierarchyDirection,
@@ -43,7 +44,6 @@ class NodeToProcess:
43
44
 
44
45
  node_id: str
45
46
  node_uuid: str
46
- profile_uuids: list[str]
47
47
 
48
48
  updated_at: str
49
49
 
@@ -142,9 +142,22 @@ class NodeCreateAllQuery(NodeQuery):
142
142
  attributes_ipnetwork: list[AttributeCreateData] = []
143
143
  attributes_indexed: list[AttributeCreateData] = []
144
144
 
145
+ if self.node.has_display_label():
146
+ attributes_indexed.append(
147
+ self.node._display_label.get_node_attribute(node=self.node, at=at).get_create_data(
148
+ node_schema=self.node.get_schema()
149
+ )
150
+ )
151
+ if self.node.has_human_friendly_id():
152
+ attributes_indexed.append(
153
+ self.node._human_friendly_id.get_node_attribute(node=self.node, at=at).get_create_data(
154
+ node_schema=self.node.get_schema()
155
+ )
156
+ )
157
+
145
158
  for attr_name in self.node._attributes:
146
159
  attr: BaseAttribute = getattr(self.node, attr_name)
147
- attr_data = attr.get_create_data()
160
+ attr_data = attr.get_create_data(node_schema=self.node.get_schema())
148
161
  node_type = attr.get_db_node_type()
149
162
 
150
163
  if AttributeDBNodeType.IPHOST in node_type:
@@ -610,6 +623,7 @@ class NodeListGetAttributeQuery(Query):
610
623
 
611
624
  async def query_init(self, db: InfrahubDatabase, **kwargs) -> None: # noqa: ARG002
612
625
  self.params["ids"] = self.ids
626
+ self.params["profile_relationship_name"] = PROFILE_NODE_RELATIONSHIP_IDENTIFIER
613
627
 
614
628
  branch_filter, branch_params = self.branch.get_query_filter_path(
615
629
  at=self.at, branch_agnostic=self.branch_agnostic
@@ -618,6 +632,7 @@ class NodeListGetAttributeQuery(Query):
618
632
 
619
633
  query = """
620
634
  MATCH (n:Node) WHERE n.uuid IN $ids
635
+ WITH n, exists((n)-[:IS_RELATED]-(:Relationship {name: $profile_relationship_name})) AS might_use_profile
621
636
  MATCH (n)-[:HAS_ATTRIBUTE]-(a:Attribute)
622
637
  """
623
638
  if self.fields:
@@ -628,27 +643,36 @@ class NodeListGetAttributeQuery(Query):
628
643
 
629
644
  query = """
630
645
  CALL (n, a) {
631
- MATCH (n)-[r:HAS_ATTRIBUTE]->(a:Attribute)
646
+ MATCH (n)-[r:HAS_ATTRIBUTE]-(a:Attribute)
632
647
  WHERE %(branch_filter)s
633
- RETURN r.status = "active" AS is_active
648
+ RETURN r AS r1
649
+ ORDER BY r.branch_level DESC, r.from DESC
650
+ LIMIT 1
651
+ }
652
+ WITH n, r1, a, might_use_profile
653
+ WHERE r1.status = "active"
654
+ WITH n, r1, a, might_use_profile
655
+ CALL (a, might_use_profile) {
656
+ OPTIONAL MATCH (a)-[r:HAS_SOURCE]->(:CoreProfile)
657
+ WHERE might_use_profile = TRUE AND %(branch_filter)s
658
+ RETURN r.status = "active" AS has_active_profile
634
659
  ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
635
660
  LIMIT 1
636
661
  }
637
- WITH n, a
638
- WHERE is_active = TRUE
662
+ WITH *, has_active_profile = TRUE AS is_from_profile
639
663
  CALL (a) {
640
- MATCH (a)-[r:HAS_VALUE]->(av:AttributeValue)
664
+ MATCH (a)-[r:HAS_VALUE]-(av:AttributeValue)
641
665
  WHERE %(branch_filter)s
642
- RETURN av, r AS r2
643
- ORDER BY r.branch_level DESC, r.from DESC, r.status ASC
666
+ RETURN r as r2, av
667
+ ORDER BY r.branch_level DESC, r.from DESC
644
668
  LIMIT 1
645
669
  }
646
- WITH n, a, av, r2
670
+ WITH n, r1, a, r2, av, is_from_profile
647
671
  WHERE r2.status = "active"
648
672
  """ % {"branch_filter": branch_filter}
649
673
  self.add_to_query(query)
650
674
 
651
- self.return_labels = ["n", "a", "av", "r2"]
675
+ self.return_labels = ["n", "a", "av", "r1", "r2", "is_from_profile"]
652
676
 
653
677
  # Add Is_Protected and Is_visible
654
678
  query = """
@@ -673,16 +697,32 @@ CALL (a) {
673
697
 
674
698
  if self.include_source:
675
699
  query = """
676
- OPTIONAL MATCH (a)-[rel_source:HAS_SOURCE]-(source)
677
- WHERE all(r IN [rel_source] WHERE ( %(branch_filter)s ))
700
+ CALL (a) {
701
+ OPTIONAL MATCH (a)-[rel_source:HAS_SOURCE]-(source)
702
+ WHERE all(r IN [rel_source] WHERE ( %(branch_filter)s ))
703
+ RETURN source, rel_source
704
+ ORDER BY rel_source.branch_level DESC, rel_source.from DESC, rel_source.status ASC
705
+ LIMIT 1
706
+ }
707
+ WITH *,
708
+ CASE WHEN rel_source.status = "active" THEN source ELSE NULL END AS source,
709
+ CASE WHEN rel_source.status = "active" THEN rel_source ELSE NULL END AS rel_source
678
710
  """ % {"branch_filter": branch_filter}
679
711
  self.add_to_query(query)
680
712
  self.return_labels.extend(["source", "rel_source"])
681
713
 
682
714
  if self.include_owner:
683
715
  query = """
684
- OPTIONAL MATCH (a)-[rel_owner:HAS_OWNER]-(owner)
685
- WHERE all(r IN [rel_owner] WHERE ( %(branch_filter)s ))
716
+ CALL (a) {
717
+ OPTIONAL MATCH (a)-[rel_owner:HAS_OWNER]-(owner)
718
+ WHERE all(r IN [rel_owner] WHERE ( %(branch_filter)s ))
719
+ RETURN owner, rel_owner
720
+ ORDER BY rel_owner.branch_level DESC, rel_owner.from DESC, rel_owner.status ASC
721
+ LIMIT 1
722
+ }
723
+ WITH *,
724
+ CASE WHEN rel_owner.status = "active" THEN owner ELSE NULL END AS owner,
725
+ CASE WHEN rel_owner.status = "active" THEN rel_owner ELSE NULL END AS rel_owner
686
726
  """ % {"branch_filter": branch_filter}
687
727
  self.add_to_query(query)
688
728
  self.return_labels.extend(["owner", "rel_owner"])
@@ -713,6 +753,7 @@ CALL (a) {
713
753
  def _extract_attribute_data(self, result: QueryResult) -> AttributeFromDB:
714
754
  attr = result.get_node("a")
715
755
  attr_value = result.get_node("av")
756
+ is_from_profile = result.get_as_type(label="is_from_profile", return_type=bool)
716
757
 
717
758
  data = AttributeFromDB(
718
759
  name=attr.get("name"),
@@ -724,6 +765,7 @@ CALL (a) {
724
765
  updated_at=result.get_rel("r2").get("from"),
725
766
  value=attr_value.get("value"),
726
767
  is_default=attr_value.get("is_default"),
768
+ is_from_profile=is_from_profile,
727
769
  content=attr_value._properties,
728
770
  branch=self.branch.name,
729
771
  flag_properties={
@@ -948,6 +990,8 @@ class NodeListGetInfoQuery(Query):
948
990
  at=self.at, branch_agnostic=self.branch_agnostic
949
991
  )
950
992
  self.params.update(branch_params)
993
+ self.params["ids"] = self.ids
994
+ self.order_by = ["n.uuid"]
951
995
 
952
996
  query = """
953
997
  MATCH p = (root:Root)<-[:IS_PART_OF]-(n:Node)
@@ -961,16 +1005,11 @@ class NodeListGetInfoQuery(Query):
961
1005
  }
962
1006
  WITH n1 as n, r1 as rb
963
1007
  WHERE rb.status = "active"
964
- OPTIONAL MATCH profile_path = (n)-[:IS_RELATED]->(profile_r:Relationship)<-[:IS_RELATED]-(profile:Node)-[:IS_PART_OF]->(:Root)
965
- WHERE profile_r.name = "node__profile"
966
- AND profile.namespace = "Profile"
967
- AND all(r in relationships(profile_path) WHERE %(branch_filter)s and r.status = "active")
968
1008
  """ % {"branch_filter": branch_filter}
969
1009
 
970
1010
  self.add_to_query(query)
971
- self.params["ids"] = self.ids
972
1011
 
973
- self.return_labels = ["collect(profile.uuid) as profile_uuids", "n", "rb"]
1012
+ self.return_labels = ["n", "rb"]
974
1013
 
975
1014
  async def get_nodes(self, db: InfrahubDatabase, duplicate: bool = False) -> AsyncIterator[NodeToProcess]:
976
1015
  """Return all the node objects as NodeToProcess."""
@@ -984,24 +1023,11 @@ class NodeListGetInfoQuery(Query):
984
1023
  schema=schema,
985
1024
  node_id=result.get_node("n").element_id,
986
1025
  node_uuid=result.get_node("n").get("uuid"),
987
- profile_uuids=[str(puuid) for puuid in result.get("profile_uuids")],
988
1026
  updated_at=result.get_rel("rb").get("from"),
989
1027
  branch=node_branch,
990
1028
  labels=list(result.get_node("n").labels),
991
1029
  )
992
1030
 
993
- def get_profile_ids_by_node_id(self) -> dict[str, list[str]]:
994
- profile_id_map: dict[str, list[str]] = {}
995
- for result in self.results:
996
- node_id = result.get_node("n").get("uuid")
997
- profile_ids = result.get("profile_uuids")
998
- if not node_id or not profile_ids:
999
- continue
1000
- if node_id not in profile_id_map:
1001
- profile_id_map[node_id] = []
1002
- profile_id_map[node_id].extend(profile_ids)
1003
- return profile_id_map
1004
-
1005
1031
 
1006
1032
  class FieldAttributeRequirementType(Enum):
1007
1033
  FILTER = "filter"
@@ -1018,7 +1044,7 @@ class FieldAttributeRequirement:
1018
1044
  types: list[FieldAttributeRequirementType] = dataclass_field(default_factory=list)
1019
1045
 
1020
1046
  @property
1021
- def supports_profile(self) -> bool:
1047
+ def is_attribute_value(self) -> bool:
1022
1048
  return bool(self.field and self.field.is_attribute and self.field_attr_name in ("value", "values", "isnull"))
1023
1049
 
1024
1050
  @property
@@ -1029,26 +1055,10 @@ class FieldAttributeRequirement:
1029
1055
  def is_order(self) -> bool:
1030
1056
  return FieldAttributeRequirementType.ORDER in self.types
1031
1057
 
1032
- @property
1033
- def is_default_query_variable(self) -> str:
1034
- return f"attr{self.index}_is_default"
1035
-
1036
1058
  @property
1037
1059
  def node_value_query_variable(self) -> str:
1038
1060
  return f"attr{self.index}_node_value"
1039
1061
 
1040
- @property
1041
- def profile_value_query_variable(self) -> str:
1042
- return f"attr{self.index}_profile_value"
1043
-
1044
- @property
1045
- def profile_final_value_query_variable(self) -> str:
1046
- return f"attr{self.index}_final_profile_value"
1047
-
1048
- @property
1049
- def final_value_query_variable(self) -> str:
1050
- return f"attr{self.index}_final_value"
1051
-
1052
1062
  @property
1053
1063
  def comparison_operator(self) -> str:
1054
1064
  if self.field_attr_name == "isnull":
@@ -1184,7 +1194,6 @@ class NodeGetListQuery(Query):
1184
1194
  self.params["node_ids"] = self.filters["ids"]
1185
1195
 
1186
1196
  field_attribute_requirements = self._get_field_requirements(disable_order=disable_order)
1187
- use_profiles = any(far for far in field_attribute_requirements if far.supports_profile)
1188
1197
  await self._add_node_filter_attributes(
1189
1198
  db=db, field_attribute_requirements=field_attribute_requirements, branch_filter=branch_filter
1190
1199
  )
@@ -1196,21 +1205,11 @@ class NodeGetListQuery(Query):
1196
1205
  for far in field_attribute_requirements:
1197
1206
  if not far.is_order:
1198
1207
  continue
1199
- if far.supports_profile:
1200
- self.order_by.append(far.final_value_query_variable)
1201
- continue
1202
1208
  self.order_by.append(far.node_value_query_variable)
1203
1209
 
1204
1210
  # Always order by uuid to guarantee pagination, see https://github.com/opsmill/infrahub/pull/4704.
1205
1211
  self.order_by.append("n.uuid")
1206
1212
 
1207
- if use_profiles:
1208
- await self._add_profiles_per_node_query(db=db, branch_filter=branch_filter)
1209
- await self._add_profile_attributes(
1210
- db=db, field_attribute_requirements=field_attribute_requirements, branch_filter=branch_filter
1211
- )
1212
- await self._add_profile_rollups(field_attribute_requirements=field_attribute_requirements)
1213
-
1214
1213
  self._add_final_filter(field_attribute_requirements=field_attribute_requirements)
1215
1214
 
1216
1215
  async def _add_node_filter_attributes(
@@ -1228,8 +1227,6 @@ class NodeGetListQuery(Query):
1228
1227
 
1229
1228
  for far in field_attribute_requirements:
1230
1229
  extra_tail_properties = {far.node_value_query_variable: "value"}
1231
- if far.supports_profile:
1232
- extra_tail_properties[far.is_default_query_variable] = "is_default"
1233
1230
  subquery, subquery_params, subquery_result_name = await build_subquery_filter(
1234
1231
  db=db,
1235
1232
  field=far.field,
@@ -1240,7 +1237,6 @@ class NodeGetListQuery(Query):
1240
1237
  branch=self.branch,
1241
1238
  subquery_idx=far.index,
1242
1239
  partial_match=self.partial_match,
1243
- support_profiles=far.supports_profile,
1244
1240
  extra_tail_properties=extra_tail_properties,
1245
1241
  )
1246
1242
  for query_var in extra_tail_properties:
@@ -1280,9 +1276,6 @@ class NodeGetListQuery(Query):
1280
1276
  for far in field_attribute_requirements:
1281
1277
  if far.field is None:
1282
1278
  continue
1283
- extra_tail_properties = {}
1284
- if far.supports_profile:
1285
- extra_tail_properties[far.is_default_query_variable] = "is_default"
1286
1279
 
1287
1280
  subquery, subquery_params, _ = await build_subquery_order(
1288
1281
  db=db,
@@ -1293,11 +1286,7 @@ class NodeGetListQuery(Query):
1293
1286
  branch=self.branch,
1294
1287
  subquery_idx=far.index,
1295
1288
  result_prefix=far.node_value_query_variable,
1296
- support_profiles=far.supports_profile,
1297
- extra_tail_properties=extra_tail_properties,
1298
1289
  )
1299
- for query_var in extra_tail_properties:
1300
- self._track_variable(query_var)
1301
1290
  self._track_variable(far.node_value_query_variable)
1302
1291
  with_str = ", ".join(self._get_tracked_variables())
1303
1292
 
@@ -1311,122 +1300,11 @@ class NodeGetListQuery(Query):
1311
1300
  self.add_to_query(sort_query)
1312
1301
  self.params.update(sort_params)
1313
1302
 
1314
- async def _add_profiles_per_node_query(self, db: InfrahubDatabase, branch_filter: str) -> None:
1315
- with_str = ", ".join(self._get_tracked_variables())
1316
- froms_str = db.render_list_comprehension(items="relationships(profile_path)", item_name="from")
1317
- profiles_per_node_query = (
1318
- """
1319
- CALL (n) {
1320
- OPTIONAL MATCH profile_path = (n)-[:IS_RELATED]->(profile_r:Relationship)<-[:IS_RELATED]-(maybe_profile_n:Node)-[:IS_PART_OF]->(:Root)
1321
- WHERE profile_r.name = "node__profile"
1322
- AND all(r in relationships(profile_path) WHERE %(branch_filter)s)
1323
- WITH
1324
- maybe_profile_n,
1325
- profile_path,
1326
- reduce(br_lvl = 0, r in relationships(profile_path) | br_lvl + r.branch_level) AS branch_level,
1327
- %(froms_str)s AS froms,
1328
- all(r in relationships(profile_path) WHERE r.status = "active") AS is_active
1329
- RETURN maybe_profile_n, is_active, branch_level, froms
1330
- }
1331
- WITH %(with_str)s, maybe_profile_n, branch_level, froms, is_active
1332
- ORDER BY n.uuid, maybe_profile_n.uuid, branch_level DESC, froms[-1] DESC, froms[-2] DESC, froms[-3] DESC
1333
- WITH %(with_str)s, maybe_profile_n, collect(is_active) as ordered_is_actives
1334
- WITH %(with_str)s, CASE
1335
- WHEN ordered_is_actives[0] = True THEN maybe_profile_n ELSE NULL
1336
- END AS profile_n
1337
- CALL (profile_n) {
1338
- OPTIONAL MATCH profile_priority_path = (profile_n)-[pr1:HAS_ATTRIBUTE]->(a:Attribute)-[pr2:HAS_VALUE]->(av:AttributeValue)
1339
- WHERE a.name = "profile_priority"
1340
- AND all(r in relationships(profile_priority_path) WHERE %(branch_filter)s and r.status = "active")
1341
- RETURN av.value as profile_priority
1342
- ORDER BY pr1.branch_level + pr2.branch_level DESC, pr2.from DESC, pr1.from DESC
1343
- LIMIT 1
1344
- }
1345
- WITH %(with_str)s, profile_n, profile_priority
1346
- """
1347
- ) % {"branch_filter": branch_filter, "with_str": with_str, "froms_str": froms_str}
1348
- self.add_to_query(profiles_per_node_query)
1349
- self._track_variable("profile_n")
1350
- self._track_variable("profile_priority")
1351
-
1352
- async def _add_profile_attributes(
1353
- self, db: InfrahubDatabase, field_attribute_requirements: list[FieldAttributeRequirement], branch_filter: str
1354
- ) -> None:
1355
- attributes_queries: list[str] = []
1356
- attributes_params: dict[str, Any] = {}
1357
- profile_attributes = [far for far in field_attribute_requirements if far.supports_profile]
1358
-
1359
- for profile_attr in profile_attributes:
1360
- if not profile_attr.field:
1361
- continue
1362
- subquery, subquery_params, _ = await build_subquery_order(
1363
- db=db,
1364
- field=profile_attr.field,
1365
- node_alias="profile_n",
1366
- name=profile_attr.field_name,
1367
- order_by=profile_attr.field_attr_name,
1368
- branch_filter=branch_filter,
1369
- branch=self.branch,
1370
- subquery_idx=profile_attr.index,
1371
- result_prefix=profile_attr.profile_value_query_variable,
1372
- support_profiles=False,
1373
- )
1374
- attributes_params.update(subquery_params)
1375
- self._track_variable(profile_attr.profile_value_query_variable)
1376
- with_str = ", ".join(self._get_tracked_variables())
1377
-
1378
- attributes_queries.append("CALL (profile_n) {")
1379
- attributes_queries.append(subquery)
1380
- attributes_queries.append("}")
1381
- attributes_queries.append(f"WITH {with_str}")
1382
-
1383
- self.add_to_query(attributes_queries)
1384
- self.params.update(attributes_params)
1385
-
1386
- async def _add_profile_rollups(self, field_attribute_requirements: list[FieldAttributeRequirement]) -> None:
1387
- profile_attributes = [far for far in field_attribute_requirements if far.supports_profile]
1388
- profile_value_collects = []
1389
- for profile_attr in profile_attributes:
1390
- self._untrack_variable(profile_attr.profile_value_query_variable)
1391
- profile_value_collects.append(
1392
- f"""head(
1393
- reduce(
1394
- non_null_values = [], v in collect({profile_attr.profile_value_query_variable}) |
1395
- CASE WHEN v IS NOT NULL AND v <> "NULL" THEN non_null_values + [v] ELSE non_null_values END
1396
- )
1397
- ) as {profile_attr.profile_final_value_query_variable}"""
1398
- )
1399
- self._untrack_variable("profile_n")
1400
- self._untrack_variable("profile_priority")
1401
- profile_rollup_with_str = ", ".join(self._get_tracked_variables() + profile_value_collects)
1402
- profile_rollup_query = f"""
1403
- ORDER BY n.uuid, profile_priority ASC, profile_n.uuid ASC
1404
- WITH {profile_rollup_with_str}
1405
- """
1406
- self.add_to_query(profile_rollup_query)
1407
- for profile_attr in profile_attributes:
1408
- self._track_variable(profile_attr.profile_final_value_query_variable)
1409
-
1410
- final_value_with = []
1411
- for profile_attr in profile_attributes:
1412
- final_value_with.append(f"""
1413
- CASE
1414
- WHEN {profile_attr.is_default_query_variable} AND {profile_attr.profile_final_value_query_variable} IS NOT NULL
1415
- THEN {profile_attr.profile_final_value_query_variable}
1416
- ELSE {profile_attr.node_value_query_variable}
1417
- END AS {profile_attr.final_value_query_variable}
1418
- """)
1419
- self._untrack_variable(profile_attr.is_default_query_variable)
1420
- self._untrack_variable(profile_attr.profile_final_value_query_variable)
1421
- self._untrack_variable(profile_attr.node_value_query_variable)
1422
- final_value_with_str = ", ".join(self._get_tracked_variables() + final_value_with)
1423
- self.add_to_query(f"WITH {final_value_with_str}")
1424
-
1425
1303
  def _add_final_filter(self, field_attribute_requirements: list[FieldAttributeRequirement]) -> None:
1426
1304
  where_parts = []
1427
1305
  where_str = ""
1428
1306
  for far in field_attribute_requirements:
1429
- if not far.is_filter or not far.supports_profile:
1307
+ if not far.is_filter or not far.is_attribute_value:
1430
1308
  continue
1431
1309
  var_name = f"final_attr_value{far.index}"
1432
1310
  self.params[var_name] = far.field_attr_comparison_value
@@ -1435,11 +1313,11 @@ class NodeGetListQuery(Query):
1435
1313
  # If the any filter is an array/list
1436
1314
  var_array = f"{var_name}_array"
1437
1315
  where_parts.append(
1438
- f"any({var_array} IN ${var_name} WHERE toLower(toString({far.final_value_query_variable})) CONTAINS toLower({var_array}))"
1316
+ f"any({var_array} IN ${var_name} WHERE toLower(toString({far.node_value_query_variable})) CONTAINS toLower({var_array}))"
1439
1317
  )
1440
1318
  else:
1441
1319
  where_parts.append(
1442
- f"toLower(toString({far.final_value_query_variable})) CONTAINS toLower(toString(${var_name}))"
1320
+ f"toLower(toString({far.node_value_query_variable})) CONTAINS toLower(toString(${var_name}))"
1443
1321
  )
1444
1322
  continue
1445
1323
  if far.field and isinstance(far.field, AttributeSchema) and far.field.kind == "List":
@@ -1448,10 +1326,10 @@ class NodeGetListQuery(Query):
1448
1326
  else:
1449
1327
  self.params[var_name] = build_regex_attrs(values=[far.field_attr_comparison_value])
1450
1328
 
1451
- where_parts.append(f"toString({far.final_value_query_variable}) =~ ${var_name}")
1329
+ where_parts.append(f"toString({far.node_value_query_variable}) =~ ${var_name}")
1452
1330
  continue
1453
1331
 
1454
- where_parts.append(f"{far.final_value_query_variable} {far.comparison_operator} ${var_name}")
1332
+ where_parts.append(f"{far.node_value_query_variable} {far.comparison_operator} ${var_name}")
1455
1333
  if where_parts:
1456
1334
  where_str = "WHERE " + " AND ".join(where_parts)
1457
1335
  self.add_to_query(where_str)