infrahub-server 1.6.3__py3-none-any.whl → 1.7.0b0__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 (161) hide show
  1. infrahub/actions/tasks.py +4 -2
  2. infrahub/api/schema.py +3 -1
  3. infrahub/artifacts/tasks.py +1 -0
  4. infrahub/auth.py +2 -2
  5. infrahub/cli/db.py +6 -6
  6. infrahub/computed_attribute/gather.py +3 -4
  7. infrahub/computed_attribute/tasks.py +23 -6
  8. infrahub/config.py +8 -0
  9. infrahub/constants/enums.py +12 -0
  10. infrahub/core/account.py +5 -8
  11. infrahub/core/attribute.py +106 -108
  12. infrahub/core/branch/models.py +44 -71
  13. infrahub/core/branch/tasks.py +5 -3
  14. infrahub/core/changelog/diff.py +1 -20
  15. infrahub/core/changelog/models.py +0 -7
  16. infrahub/core/constants/__init__.py +17 -0
  17. infrahub/core/constants/database.py +0 -1
  18. infrahub/core/constants/schema.py +0 -1
  19. infrahub/core/convert_object_type/repository_conversion.py +3 -4
  20. infrahub/core/diff/data_check_synchronizer.py +3 -2
  21. infrahub/core/diff/enricher/cardinality_one.py +1 -1
  22. infrahub/core/diff/merger/merger.py +27 -1
  23. infrahub/core/diff/merger/serializer.py +3 -10
  24. infrahub/core/diff/model/diff.py +1 -1
  25. infrahub/core/diff/query/merge.py +376 -135
  26. infrahub/core/graph/__init__.py +1 -1
  27. infrahub/core/graph/constraints.py +2 -2
  28. infrahub/core/graph/schema.py +2 -12
  29. infrahub/core/manager.py +132 -126
  30. infrahub/core/metadata/__init__.py +0 -0
  31. infrahub/core/metadata/interface.py +37 -0
  32. infrahub/core/metadata/model.py +31 -0
  33. infrahub/core/metadata/query/__init__.py +0 -0
  34. infrahub/core/metadata/query/node_metadata.py +301 -0
  35. infrahub/core/migrations/graph/__init__.py +4 -0
  36. infrahub/core/migrations/graph/m013_convert_git_password_credential.py +3 -8
  37. infrahub/core/migrations/graph/m017_add_core_profile.py +5 -2
  38. infrahub/core/migrations/graph/m018_uniqueness_nulls.py +2 -1
  39. infrahub/core/migrations/graph/m019_restore_rels_to_time.py +0 -10
  40. infrahub/core/migrations/graph/m020_duplicate_edges.py +0 -8
  41. infrahub/core/migrations/graph/m025_uniqueness_nulls.py +2 -1
  42. infrahub/core/migrations/graph/m026_0000_prefix_fix.py +2 -1
  43. infrahub/core/migrations/graph/m029_duplicates_cleanup.py +0 -1
  44. infrahub/core/migrations/graph/m031_check_number_attributes.py +2 -2
  45. infrahub/core/migrations/graph/m038_redo_0000_prefix_fix.py +2 -1
  46. infrahub/core/migrations/graph/m049_remove_is_visible_relationship.py +38 -0
  47. infrahub/core/migrations/graph/m050_backfill_vertex_metadata.py +168 -0
  48. infrahub/core/migrations/query/attribute_add.py +17 -6
  49. infrahub/core/migrations/query/attribute_remove.py +19 -5
  50. infrahub/core/migrations/query/attribute_rename.py +21 -5
  51. infrahub/core/migrations/query/node_duplicate.py +19 -4
  52. infrahub/core/migrations/schema/attribute_kind_update.py +25 -7
  53. infrahub/core/migrations/schema/attribute_supports_profile.py +3 -1
  54. infrahub/core/migrations/schema/models.py +3 -0
  55. infrahub/core/migrations/schema/node_attribute_add.py +4 -1
  56. infrahub/core/migrations/schema/node_remove.py +24 -2
  57. infrahub/core/migrations/schema/tasks.py +4 -1
  58. infrahub/core/migrations/shared.py +13 -6
  59. infrahub/core/models.py +6 -6
  60. infrahub/core/node/__init__.py +156 -57
  61. infrahub/core/node/create.py +7 -3
  62. infrahub/core/node/standard.py +100 -14
  63. infrahub/core/property.py +0 -1
  64. infrahub/core/protocols_base.py +6 -2
  65. infrahub/core/query/__init__.py +6 -7
  66. infrahub/core/query/attribute.py +161 -46
  67. infrahub/core/query/branch.py +57 -69
  68. infrahub/core/query/diff.py +4 -4
  69. infrahub/core/query/node.py +618 -180
  70. infrahub/core/query/relationship.py +449 -300
  71. infrahub/core/query/standard_node.py +25 -5
  72. infrahub/core/query/utils.py +2 -4
  73. infrahub/core/relationship/constraints/profiles_removal.py +168 -0
  74. infrahub/core/relationship/model.py +293 -139
  75. infrahub/core/schema/attribute_parameters.py +1 -28
  76. infrahub/core/schema/attribute_schema.py +17 -11
  77. infrahub/core/schema/manager.py +63 -43
  78. infrahub/core/schema/relationship_schema.py +6 -2
  79. infrahub/core/schema/schema_branch.py +48 -76
  80. infrahub/core/task/task.py +4 -2
  81. infrahub/core/utils.py +0 -22
  82. infrahub/core/validators/attribute/kind.py +2 -5
  83. infrahub/core/validators/determiner.py +3 -3
  84. infrahub/database/__init__.py +3 -3
  85. infrahub/dependencies/builder/constraint/grouped/node_runner.py +2 -0
  86. infrahub/dependencies/builder/constraint/relationship_manager/profiles_removal.py +8 -0
  87. infrahub/dependencies/registry.py +2 -0
  88. infrahub/display_labels/tasks.py +12 -3
  89. infrahub/git/integrator.py +18 -18
  90. infrahub/git/tasks.py +1 -1
  91. infrahub/graphql/app.py +2 -2
  92. infrahub/graphql/constants.py +3 -0
  93. infrahub/graphql/context.py +1 -1
  94. infrahub/graphql/initialization.py +11 -0
  95. infrahub/graphql/loaders/account.py +134 -0
  96. infrahub/graphql/loaders/node.py +5 -12
  97. infrahub/graphql/loaders/peers.py +5 -7
  98. infrahub/graphql/manager.py +158 -18
  99. infrahub/graphql/metadata.py +91 -0
  100. infrahub/graphql/models.py +33 -3
  101. infrahub/graphql/mutations/account.py +5 -5
  102. infrahub/graphql/mutations/attribute.py +0 -2
  103. infrahub/graphql/mutations/branch.py +9 -5
  104. infrahub/graphql/mutations/computed_attribute.py +1 -1
  105. infrahub/graphql/mutations/display_label.py +1 -1
  106. infrahub/graphql/mutations/hfid.py +1 -1
  107. infrahub/graphql/mutations/ipam.py +4 -6
  108. infrahub/graphql/mutations/main.py +9 -4
  109. infrahub/graphql/mutations/profile.py +16 -22
  110. infrahub/graphql/mutations/proposed_change.py +4 -4
  111. infrahub/graphql/mutations/relationship.py +40 -10
  112. infrahub/graphql/mutations/repository.py +14 -12
  113. infrahub/graphql/mutations/schema.py +2 -2
  114. infrahub/graphql/queries/branch.py +62 -6
  115. infrahub/graphql/queries/diff/tree.py +5 -5
  116. infrahub/graphql/resolvers/account_metadata.py +84 -0
  117. infrahub/graphql/resolvers/ipam.py +6 -8
  118. infrahub/graphql/resolvers/many_relationship.py +77 -35
  119. infrahub/graphql/resolvers/resolver.py +16 -12
  120. infrahub/graphql/resolvers/single_relationship.py +87 -23
  121. infrahub/graphql/subscription/graphql_query.py +2 -0
  122. infrahub/graphql/types/__init__.py +0 -1
  123. infrahub/graphql/types/attribute.py +10 -5
  124. infrahub/graphql/types/branch.py +40 -53
  125. infrahub/graphql/types/enums.py +3 -0
  126. infrahub/graphql/types/metadata.py +28 -0
  127. infrahub/graphql/types/node.py +22 -2
  128. infrahub/graphql/types/relationship.py +10 -2
  129. infrahub/graphql/types/standard_node.py +4 -3
  130. infrahub/hfid/tasks.py +12 -3
  131. infrahub/profiles/gather.py +56 -0
  132. infrahub/profiles/mandatory_fields_checker.py +116 -0
  133. infrahub/profiles/models.py +66 -0
  134. infrahub/profiles/node_applier.py +153 -12
  135. infrahub/profiles/queries/get_profile_data.py +143 -31
  136. infrahub/profiles/tasks.py +79 -27
  137. infrahub/profiles/triggers.py +22 -0
  138. infrahub/proposed_change/tasks.py +4 -1
  139. infrahub/tasks/artifact.py +1 -0
  140. infrahub/transformations/tasks.py +2 -2
  141. infrahub/trigger/catalogue.py +2 -0
  142. infrahub/trigger/models.py +1 -0
  143. infrahub/trigger/setup.py +3 -3
  144. infrahub/trigger/tasks.py +3 -0
  145. infrahub/validators/tasks.py +1 -0
  146. infrahub/webhook/models.py +1 -1
  147. infrahub/webhook/tasks.py +1 -1
  148. infrahub/workers/dependencies.py +9 -3
  149. infrahub/workers/infrahub_async.py +13 -4
  150. infrahub/workflows/catalogue.py +19 -0
  151. infrahub_sdk/node/constants.py +1 -0
  152. infrahub_sdk/node/related_node.py +13 -4
  153. infrahub_sdk/node/relationship.py +8 -0
  154. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0b0.dist-info}/METADATA +17 -16
  155. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0b0.dist-info}/RECORD +161 -143
  156. infrahub_testcontainers/container.py +3 -3
  157. infrahub_testcontainers/docker-compose-cluster.test.yml +7 -7
  158. infrahub_testcontainers/docker-compose.test.yml +13 -5
  159. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0b0.dist-info}/WHEEL +0 -0
  160. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0b0.dist-info}/entry_points.txt +0 -0
  161. {infrahub_server-1.6.3.dist-info → infrahub_server-1.7.0b0.dist-info}/licenses/LICENSE.txt +0 -0
infrahub/core/manager.py CHANGED
@@ -5,7 +5,14 @@ from typing import TYPE_CHECKING, Any, Iterable, Literal, TypeVar, overload
5
5
 
6
6
  from infrahub_sdk.utils import deep_merge_dict, is_valid_uuid
7
7
 
8
- from infrahub.core.constants import InfrahubKind, RelationshipCardinality, RelationshipDirection
8
+ from infrahub.core.constants import (
9
+ SYSTEM_USER_ID,
10
+ InfrahubKind,
11
+ MetadataOptions,
12
+ RelationshipCardinality,
13
+ RelationshipDirection,
14
+ )
15
+ from infrahub.core.metadata.model import MetadataQueryOptions
9
16
  from infrahub.core.node import Node
10
17
  from infrahub.core.node.delete_validator import NodeDeleteValidator
11
18
  from infrahub.core.query.node import (
@@ -21,6 +28,7 @@ from infrahub.core.query.node import (
21
28
  from infrahub.core.query.relationship import RelationshipGetPeerQuery
22
29
  from infrahub.core.registry import registry
23
30
  from infrahub.core.relationship import Relationship, RelationshipManager
31
+ from infrahub.core.relationship.model import PeerWithRelationshipMetadata
24
32
  from infrahub.core.schema import (
25
33
  GenericSchema,
26
34
  MainSchemaTypes,
@@ -88,8 +96,7 @@ class NodeManager:
88
96
  limit: int | None = ...,
89
97
  at: Timestamp | str | None = ...,
90
98
  branch: Branch | str | None = ...,
91
- include_source: bool = ...,
92
- include_owner: bool = ...,
99
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
93
100
  prefetch_relationships: bool = ...,
94
101
  account=...,
95
102
  partial_match: bool = ...,
@@ -109,8 +116,7 @@ class NodeManager:
109
116
  limit: int | None = ...,
110
117
  at: Timestamp | str | None = ...,
111
118
  branch: Branch | str | None = ...,
112
- include_source: bool = ...,
113
- include_owner: bool = ...,
119
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
114
120
  prefetch_relationships: bool = ...,
115
121
  account=...,
116
122
  partial_match: bool = ...,
@@ -129,8 +135,7 @@ class NodeManager:
129
135
  limit: int | None = None,
130
136
  at: Timestamp | str | None = None,
131
137
  branch: Branch | str | None = None,
132
- include_source: bool = False,
133
- include_owner: bool = False,
138
+ include_metadata: MetadataQueryOptions | MetadataOptions = MetadataOptions.NONE,
134
139
  prefetch_relationships: bool = False,
135
140
  account=None,
136
141
  partial_match: bool = False,
@@ -164,8 +169,7 @@ class NodeManager:
164
169
  fields=fields,
165
170
  at=at,
166
171
  branch=branch,
167
- include_source=include_source,
168
- include_owner=include_owner,
172
+ include_metadata=include_metadata,
169
173
  prefetch_relationships=prefetch_relationships,
170
174
  account=account,
171
175
  branch_agnostic=branch_agnostic,
@@ -209,10 +213,8 @@ class NodeManager:
209
213
  ids=node_ids,
210
214
  fields=fields,
211
215
  branch=branch,
212
- account=account,
213
216
  at=at,
214
- include_source=include_source,
215
- include_owner=include_owner,
217
+ include_metadata=include_metadata,
216
218
  db=db,
217
219
  prefetch_relationships=prefetch_relationships,
218
220
  branch_agnostic=branch_agnostic,
@@ -276,15 +278,14 @@ class NodeManager:
276
278
  branch = await registry.get_branch(branch=branch, db=db)
277
279
  at = Timestamp(at)
278
280
 
279
- rel = Relationship(schema=schema, branch=branch, node_id="PLACEHOLDER")
280
-
281
281
  query = await RelationshipGetPeerQuery.init(
282
282
  db=db,
283
+ branch=branch,
283
284
  source_ids=ids,
284
285
  source_kind=source_kind,
285
286
  schema=schema,
286
287
  filters=filters,
287
- rel=rel,
288
+ rel=Relationship,
288
289
  at=at,
289
290
  branch_agnostic=branch_agnostic,
290
291
  )
@@ -305,25 +306,29 @@ class NodeManager:
305
306
  branch: Branch | str | None = None,
306
307
  branch_agnostic: bool = False,
307
308
  fetch_peers: bool = False,
308
- include_source: bool = False,
309
- include_owner: bool = False,
309
+ include_metadata: MetadataQueryOptions | MetadataOptions = MetadataOptions.NONE,
310
310
  ) -> list[Relationship]:
311
311
  branch = await registry.get_branch(branch=branch, db=db)
312
312
  at = Timestamp(at)
313
313
 
314
- rel = Relationship(schema=schema, branch=branch, node_id="PLACEHOLDER")
315
-
314
+ relationship_metadata_options = (
315
+ include_metadata.relationship_level
316
+ if isinstance(include_metadata, MetadataQueryOptions)
317
+ else include_metadata
318
+ )
316
319
  query = await RelationshipGetPeerQuery.init(
317
320
  db=db,
321
+ branch=branch,
318
322
  source_ids=ids,
319
323
  source_kind=source_kind,
320
324
  schema=schema,
321
325
  filters=filters,
322
- rel=rel,
326
+ rel=Relationship,
323
327
  offset=offset,
324
328
  limit=limit,
325
329
  at=at,
326
330
  branch_agnostic=branch_agnostic,
331
+ include_metadata=relationship_metadata_options,
327
332
  )
328
333
  await query.execute(db=db)
329
334
 
@@ -354,17 +359,21 @@ class NodeManager:
354
359
  at=at,
355
360
  branch=branch,
356
361
  branch_agnostic=branch_agnostic,
357
- include_source=include_source,
358
- include_owner=include_owner,
362
+ include_metadata=include_metadata,
359
363
  )
360
364
 
361
365
  results = []
362
366
  for peer in peers_info:
363
- result = Relationship(schema=schema, branch=branch, at=at, node_id=peer.source_id).load(
367
+ result = Relationship(
368
+ schema=schema,
369
+ branch=branch,
370
+ source_kind=peer.source_kind,
371
+ at=at,
372
+ node_id=peer.source_id,
373
+ ).load(
364
374
  db=db,
365
375
  id=peer.rel_node_id,
366
376
  db_id=peer.rel_node_db_id,
367
- updated_at=peer.updated_at,
368
377
  data=peer,
369
378
  )
370
379
  if fetch_peers:
@@ -435,7 +444,12 @@ class NodeManager:
435
444
  return {}
436
445
 
437
446
  return await cls.get_many(
438
- db=db, ids=peers_ids, fields=fields, at=at, branch=branch, include_owner=True, include_source=True
447
+ db=db,
448
+ ids=peers_ids,
449
+ fields=fields,
450
+ at=at,
451
+ branch=branch,
452
+ include_metadata=MetadataOptions.LINKED_NODES,
439
453
  )
440
454
 
441
455
  @overload
@@ -479,8 +493,7 @@ class NodeManager:
479
493
  id=id,
480
494
  branch=branch,
481
495
  at=at,
482
- include_owner=True,
483
- include_source=True,
496
+ include_metadata=MetadataOptions.LINKED_NODES,
484
497
  raise_on_error=True,
485
498
  )
486
499
 
@@ -491,8 +504,7 @@ class NodeManager:
491
504
  hfid=hfid,
492
505
  branch=branch,
493
506
  at=at,
494
- include_owner=True,
495
- include_source=True,
507
+ include_metadata=MetadataOptions.LINKED_NODES,
496
508
  raise_on_error=True,
497
509
  )
498
510
 
@@ -503,8 +515,7 @@ class NodeManager:
503
515
  id=id,
504
516
  branch=branch,
505
517
  at=at,
506
- include_owner=True,
507
- include_source=True,
518
+ include_metadata=MetadataOptions.LINKED_NODES,
508
519
  raise_on_error=True,
509
520
  )
510
521
 
@@ -521,8 +532,7 @@ class NodeManager:
521
532
  fields: dict | None = ...,
522
533
  at: Timestamp | str | None = ...,
523
534
  branch: Branch | str | None = ...,
524
- include_source: bool = ...,
525
- include_owner: bool = ...,
535
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
526
536
  prefetch_relationships: bool = ...,
527
537
  account=...,
528
538
  branch_agnostic: bool = ...,
@@ -539,8 +549,7 @@ class NodeManager:
539
549
  fields: dict | None = ...,
540
550
  at: Timestamp | str | None = ...,
541
551
  branch: Branch | str | None = ...,
542
- include_source: bool = ...,
543
- include_owner: bool = ...,
552
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
544
553
  prefetch_relationships: bool = ...,
545
554
  account=...,
546
555
  branch_agnostic: bool = ...,
@@ -557,8 +566,7 @@ class NodeManager:
557
566
  fields: dict | None = ...,
558
567
  at: Timestamp | str | None = ...,
559
568
  branch: Branch | str | None = ...,
560
- include_source: bool = ...,
561
- include_owner: bool = ...,
569
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
562
570
  prefetch_relationships: bool = ...,
563
571
  account=...,
564
572
  branch_agnostic: bool = ...,
@@ -575,8 +583,7 @@ class NodeManager:
575
583
  fields: dict | None = ...,
576
584
  at: Timestamp | str | None = ...,
577
585
  branch: Branch | str | None = ...,
578
- include_source: bool = ...,
579
- include_owner: bool = ...,
586
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
580
587
  prefetch_relationships: bool = ...,
581
588
  account=...,
582
589
  branch_agnostic: bool = ...,
@@ -593,8 +600,7 @@ class NodeManager:
593
600
  fields: dict | None = ...,
594
601
  at: Timestamp | str | None = ...,
595
602
  branch: Branch | str | None = ...,
596
- include_source: bool = ...,
597
- include_owner: bool = ...,
603
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
598
604
  prefetch_relationships: bool = ...,
599
605
  account=...,
600
606
  branch_agnostic: bool = ...,
@@ -611,8 +617,7 @@ class NodeManager:
611
617
  fields: dict | None = ...,
612
618
  at: Timestamp | str | None = ...,
613
619
  branch: Branch | str | None = ...,
614
- include_source: bool = ...,
615
- include_owner: bool = ...,
620
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
616
621
  prefetch_relationships: bool = ...,
617
622
  account=...,
618
623
  branch_agnostic: bool = ...,
@@ -628,8 +633,7 @@ class NodeManager:
628
633
  fields: dict | None = None,
629
634
  at: Timestamp | str | None = None,
630
635
  branch: Branch | str | None = None,
631
- include_source: bool = False,
632
- include_owner: bool = False,
636
+ include_metadata: MetadataQueryOptions | MetadataOptions = MetadataOptions.NONE,
633
637
  prefetch_relationships: bool = False,
634
638
  account=None,
635
639
  branch_agnostic: bool = False,
@@ -651,8 +655,7 @@ class NodeManager:
651
655
  filters={node_schema.default_filter: id},
652
656
  branch=branch,
653
657
  at=at,
654
- include_owner=include_owner,
655
- include_source=include_source,
658
+ include_metadata=include_metadata,
656
659
  prefetch_relationships=prefetch_relationships,
657
660
  account=account,
658
661
  branch_agnostic=branch_agnostic,
@@ -689,8 +692,7 @@ class NodeManager:
689
692
  fields: dict | None = ...,
690
693
  at: Timestamp | str | None = ...,
691
694
  branch: Branch | str | None = ...,
692
- include_source: bool = ...,
693
- include_owner: bool = ...,
695
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
694
696
  prefetch_relationships: bool = ...,
695
697
  account=...,
696
698
  ) -> SchemaProtocol | None: ...
@@ -706,8 +708,7 @@ class NodeManager:
706
708
  fields: dict | None = ...,
707
709
  at: Timestamp | str | None = ...,
708
710
  branch: Branch | str | None = ...,
709
- include_source: bool = ...,
710
- include_owner: bool = ...,
711
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
711
712
  prefetch_relationships: bool = ...,
712
713
  account=...,
713
714
  branch_agnostic: bool = ...,
@@ -724,8 +725,7 @@ class NodeManager:
724
725
  fields: dict | None = ...,
725
726
  at: Timestamp | str | None = ...,
726
727
  branch: Branch | str | None = ...,
727
- include_source: bool = ...,
728
- include_owner: bool = ...,
728
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
729
729
  prefetch_relationships: bool = ...,
730
730
  account=...,
731
731
  branch_agnostic: bool = ...,
@@ -742,8 +742,7 @@ class NodeManager:
742
742
  fields: dict | None = ...,
743
743
  at: Timestamp | str | None = ...,
744
744
  branch: Branch | str | None = ...,
745
- include_source: bool = ...,
746
- include_owner: bool = ...,
745
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
747
746
  prefetch_relationships: bool = ...,
748
747
  account=...,
749
748
  branch_agnostic: bool = ...,
@@ -760,8 +759,7 @@ class NodeManager:
760
759
  fields: dict | None = ...,
761
760
  at: Timestamp | str | None = ...,
762
761
  branch: Branch | str | None = ...,
763
- include_source: bool = ...,
764
- include_owner: bool = ...,
762
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
765
763
  prefetch_relationships: bool = ...,
766
764
  account=...,
767
765
  branch_agnostic: bool = ...,
@@ -778,8 +776,7 @@ class NodeManager:
778
776
  fields: dict | None = ...,
779
777
  at: Timestamp | str | None = ...,
780
778
  branch: Branch | str | None = ...,
781
- include_source: bool = ...,
782
- include_owner: bool = ...,
779
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
783
780
  prefetch_relationships: bool = ...,
784
781
  account=...,
785
782
  branch_agnostic: bool = ...,
@@ -795,15 +792,13 @@ class NodeManager:
795
792
  fields: dict | None = None,
796
793
  at: Timestamp | str | None = None,
797
794
  branch: Branch | str | None = None,
798
- include_source: bool = False,
799
- include_owner: bool = False,
795
+ include_metadata: MetadataQueryOptions | MetadataOptions = MetadataOptions.NONE,
800
796
  prefetch_relationships: bool = False,
801
797
  account=None,
802
798
  branch_agnostic: bool = False,
803
799
  ) -> Node | SchemaProtocol | None:
804
800
  branch = await registry.get_branch(branch=branch, db=db)
805
801
  at = Timestamp(at)
806
-
807
802
  node_schema = get_schema(db=db, branch=branch, node_schema=kind)
808
803
  kind_str = node_schema.kind
809
804
 
@@ -833,7 +828,8 @@ class NodeManager:
833
828
  rel_schema = path.related_schema
834
829
  # Keep the relationship attribute path and parse it
835
830
  path = rel_schema.parse_schema_path(
836
- path=key.split("__", maxsplit=1)[1], schema=registry.schema.get_schema_branch(name=branch.name)
831
+ path=key.split("__", maxsplit=1)[1],
832
+ schema=registry.schema.get_schema_branch(name=branch.name),
837
833
  )
838
834
 
839
835
  filters[key] = path.active_attribute_schema.get_class().deserialize_from_string(item)
@@ -846,8 +842,7 @@ class NodeManager:
846
842
  filters=filters,
847
843
  branch=branch,
848
844
  at=at,
849
- include_owner=include_owner,
850
- include_source=include_source,
845
+ include_metadata=include_metadata,
851
846
  prefetch_relationships=prefetch_relationships,
852
847
  account=account,
853
848
  branch_agnostic=branch_agnostic,
@@ -879,8 +874,7 @@ class NodeManager:
879
874
  fields: dict | None = ...,
880
875
  at: Timestamp | str | None = ...,
881
876
  branch: Branch | str | None = ...,
882
- include_source: bool = ...,
883
- include_owner: bool = ...,
877
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
884
878
  prefetch_relationships: bool = ...,
885
879
  account=...,
886
880
  branch_agnostic: bool = ...,
@@ -896,8 +890,7 @@ class NodeManager:
896
890
  fields: dict | None = ...,
897
891
  at: Timestamp | str | None = ...,
898
892
  branch: Branch | str | None = ...,
899
- include_source: bool = ...,
900
- include_owner: bool = ...,
893
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
901
894
  prefetch_relationships: bool = ...,
902
895
  account=...,
903
896
  branch_agnostic: bool = ...,
@@ -912,8 +905,7 @@ class NodeManager:
912
905
  fields: dict | None = None,
913
906
  at: Timestamp | str | None = None,
914
907
  branch: Branch | str | None = None,
915
- include_source: bool = False,
916
- include_owner: bool = False,
908
+ include_metadata: MetadataQueryOptions | MetadataOptions = MetadataOptions.NONE,
917
909
  prefetch_relationships: bool = False,
918
910
  account=None,
919
911
  branch_agnostic: bool = False,
@@ -926,11 +918,9 @@ class NodeManager:
926
918
  fields=fields,
927
919
  at=at,
928
920
  branch=branch,
929
- include_owner=include_owner,
930
- include_source=include_source,
921
+ include_metadata=include_metadata,
931
922
  db=db,
932
923
  prefetch_relationships=prefetch_relationships,
933
- account=account,
934
924
  branch_agnostic=branch_agnostic,
935
925
  )
936
926
  if node:
@@ -943,8 +933,7 @@ class NodeManager:
943
933
  fields=fields,
944
934
  at=at,
945
935
  branch=branch,
946
- include_source=include_source,
947
- include_owner=include_owner,
936
+ include_metadata=include_metadata,
948
937
  prefetch_relationships=prefetch_relationships,
949
938
  account=account,
950
939
  branch_agnostic=branch_agnostic,
@@ -964,10 +953,8 @@ class NodeManager:
964
953
  fields: dict | None = ...,
965
954
  at: Timestamp | str | None = ...,
966
955
  branch: Branch | str | None = ...,
967
- include_source: bool = ...,
968
- include_owner: bool = ...,
956
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
969
957
  prefetch_relationships: bool = ...,
970
- account=...,
971
958
  branch_agnostic: bool = ...,
972
959
  ) -> SchemaProtocol | None: ...
973
960
 
@@ -982,10 +969,8 @@ class NodeManager:
982
969
  fields: dict | None = ...,
983
970
  at: Timestamp | str | None = ...,
984
971
  branch: Branch | str | None = ...,
985
- include_source: bool = ...,
986
- include_owner: bool = ...,
972
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
987
973
  prefetch_relationships: bool = ...,
988
- account=...,
989
974
  branch_agnostic: bool = ...,
990
975
  ) -> SchemaProtocol: ...
991
976
 
@@ -1000,10 +985,8 @@ class NodeManager:
1000
985
  fields: dict | None = ...,
1001
986
  at: Timestamp | str | None = ...,
1002
987
  branch: Branch | str | None = ...,
1003
- include_source: bool = ...,
1004
- include_owner: bool = ...,
988
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
1005
989
  prefetch_relationships: bool = ...,
1006
- account=...,
1007
990
  branch_agnostic: bool = ...,
1008
991
  ) -> SchemaProtocol: ...
1009
992
 
@@ -1018,10 +1001,8 @@ class NodeManager:
1018
1001
  fields: dict | None = ...,
1019
1002
  at: Timestamp | str | None = ...,
1020
1003
  branch: Branch | str | None = ...,
1021
- include_source: bool = ...,
1022
- include_owner: bool = ...,
1004
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
1023
1005
  prefetch_relationships: bool = ...,
1024
- account=...,
1025
1006
  branch_agnostic: bool = ...,
1026
1007
  ) -> Node: ...
1027
1008
 
@@ -1036,10 +1017,8 @@ class NodeManager:
1036
1017
  fields: dict | None = ...,
1037
1018
  at: Timestamp | str | None = ...,
1038
1019
  branch: Branch | str | None = ...,
1039
- include_source: bool = ...,
1040
- include_owner: bool = ...,
1020
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
1041
1021
  prefetch_relationships: bool = ...,
1042
- account=...,
1043
1022
  branch_agnostic: bool = ...,
1044
1023
  ) -> Node | None: ...
1045
1024
 
@@ -1054,10 +1033,8 @@ class NodeManager:
1054
1033
  fields: dict | None = ...,
1055
1034
  at: Timestamp | str | None = ...,
1056
1035
  branch: Branch | str | None = ...,
1057
- include_source: bool = ...,
1058
- include_owner: bool = ...,
1036
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
1059
1037
  prefetch_relationships: bool = ...,
1060
- account=...,
1061
1038
  branch_agnostic: bool = ...,
1062
1039
  ) -> Node | None: ...
1063
1040
 
@@ -1072,10 +1049,8 @@ class NodeManager:
1072
1049
  fields: dict | None = ...,
1073
1050
  at: Timestamp | str | None = ...,
1074
1051
  branch: Branch | str | None = ...,
1075
- include_source: bool = ...,
1076
- include_owner: bool = ...,
1052
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
1077
1053
  prefetch_relationships: bool = ...,
1078
- account=...,
1079
1054
  branch_agnostic: bool = ...,
1080
1055
  ) -> Node: ...
1081
1056
 
@@ -1090,10 +1065,8 @@ class NodeManager:
1090
1065
  fields: dict | None = ...,
1091
1066
  at: Timestamp | str | None = ...,
1092
1067
  branch: Branch | str | None = ...,
1093
- include_source: bool = ...,
1094
- include_owner: bool = ...,
1068
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
1095
1069
  prefetch_relationships: bool = ...,
1096
- account=...,
1097
1070
  branch_agnostic: bool = ...,
1098
1071
  ) -> Node | None: ...
1099
1072
 
@@ -1108,10 +1081,8 @@ class NodeManager:
1108
1081
  fields: dict | None = ...,
1109
1082
  at: Timestamp | str | None = ...,
1110
1083
  branch: Branch | str | None = ...,
1111
- include_source: bool = ...,
1112
- include_owner: bool = ...,
1084
+ include_metadata: MetadataQueryOptions | MetadataOptions = ...,
1113
1085
  prefetch_relationships: bool = ...,
1114
- account=...,
1115
1086
  branch_agnostic: bool = ...,
1116
1087
  ) -> Node | None: ...
1117
1088
 
@@ -1125,10 +1096,8 @@ class NodeManager:
1125
1096
  fields: dict | None = None,
1126
1097
  at: Timestamp | str | None = None,
1127
1098
  branch: Branch | str | None = None,
1128
- include_source: bool = False,
1129
- include_owner: bool = False,
1099
+ include_metadata: MetadataQueryOptions | MetadataOptions = MetadataOptions.NONE,
1130
1100
  prefetch_relationships: bool = False,
1131
- account=None,
1132
1101
  branch_agnostic: bool = False,
1133
1102
  ) -> Node | SchemaProtocol | None:
1134
1103
  """Return one node based on its ID."""
@@ -1139,9 +1108,7 @@ class NodeManager:
1139
1108
  fields=fields,
1140
1109
  at=at,
1141
1110
  branch=branch,
1142
- include_source=include_source,
1143
- include_owner=include_owner,
1144
- account=account,
1111
+ include_metadata=include_metadata,
1145
1112
  prefetch_relationships=prefetch_relationships,
1146
1113
  db=db,
1147
1114
  branch_agnostic=branch_agnostic,
@@ -1189,10 +1156,8 @@ class NodeManager:
1189
1156
  fields: dict | None = None,
1190
1157
  at: Timestamp | str | None = None,
1191
1158
  branch: Branch | str | None = None,
1192
- include_source: bool = False,
1193
- include_owner: bool = False,
1159
+ include_metadata: MetadataQueryOptions | MetadataOptions = MetadataOptions.NONE,
1194
1160
  prefetch_relationships: bool = False,
1195
- account=None,
1196
1161
  branch_agnostic: bool = False,
1197
1162
  ) -> dict[str, Node]:
1198
1163
  """Return a list of nodes based on their IDs."""
@@ -1200,22 +1165,34 @@ class NodeManager:
1200
1165
  branch = await registry.get_branch(branch=branch, db=db)
1201
1166
  at = Timestamp(at)
1202
1167
 
1168
+ if not ids:
1169
+ return {}
1170
+
1203
1171
  # Query all nodes
1172
+ node_metadata_options = (
1173
+ include_metadata.node_level if isinstance(include_metadata, MetadataQueryOptions) else include_metadata
1174
+ )
1204
1175
  query = await NodeListGetInfoQuery.init(
1205
- db=db, ids=ids, branch=branch, account=account, at=at, branch_agnostic=branch_agnostic
1176
+ db=db,
1177
+ ids=ids,
1178
+ branch=branch,
1179
+ at=at,
1180
+ branch_agnostic=branch_agnostic,
1181
+ include_metadata=node_metadata_options,
1206
1182
  )
1207
1183
  await query.execute(db=db)
1208
1184
  nodes_info_by_id: dict[str, NodeToProcess] = {node.node_uuid: node async for node in query.get_nodes(db=db)}
1209
1185
 
1210
1186
  # Query list of all Attributes
1187
+ attribute_metadata_options = (
1188
+ include_metadata.attribute_level if isinstance(include_metadata, MetadataQueryOptions) else include_metadata
1189
+ )
1211
1190
  query = await NodeListGetAttributeQuery.init(
1212
1191
  db=db,
1213
1192
  ids=list(nodes_info_by_id.keys()),
1214
1193
  fields=fields,
1215
1194
  branch=branch,
1216
- include_source=include_source,
1217
- include_owner=include_owner,
1218
- account=account,
1195
+ include_metadata=attribute_metadata_options,
1219
1196
  at=at,
1220
1197
  branch_agnostic=branch_agnostic,
1221
1198
  )
@@ -1232,7 +1209,6 @@ class NodeManager:
1232
1209
  new_node_data: dict[str, str | AttributeFromDB] = {
1233
1210
  "db_id": node.node_id,
1234
1211
  "id": node_id,
1235
- "updated_at": node.updated_at,
1236
1212
  }
1237
1213
 
1238
1214
  if not node.schema:
@@ -1253,17 +1229,26 @@ class NodeManager:
1253
1229
  node_branch = await registry.get_branch(db=db, branch=node.branch)
1254
1230
  item = await node_class.init(schema=node.schema, branch=node_branch, at=at, db=db)
1255
1231
  await item.load(**new_node_data, db=db)
1232
+ item._set_created_at(node.created_at)
1233
+ item._set_created_by(node.created_by)
1234
+ item._set_updated_at(node.updated_at)
1235
+ item._set_updated_by(node.updated_by)
1256
1236
 
1257
1237
  nodes[node_id] = item
1258
1238
 
1239
+ relationships_metadata_options = (
1240
+ include_metadata.relationship_level
1241
+ if isinstance(include_metadata, MetadataQueryOptions)
1242
+ else include_metadata
1243
+ )
1244
+
1259
1245
  await cls._enrich_node_dicts_with_relationships(
1260
1246
  db=db,
1261
1247
  branch=branch,
1262
1248
  at=at,
1263
1249
  nodes_by_id=nodes,
1264
1250
  branch_agnostic=branch_agnostic,
1265
- include_owner=include_owner,
1266
- include_source=include_source,
1251
+ include_metadata=relationships_metadata_options,
1267
1252
  prefetch_relationships=prefetch_relationships,
1268
1253
  fields=fields,
1269
1254
  )
@@ -1278,8 +1263,7 @@ class NodeManager:
1278
1263
  at: Timestamp,
1279
1264
  nodes_by_id: dict[str, Node],
1280
1265
  branch_agnostic: bool,
1281
- include_owner: bool,
1282
- include_source: bool,
1266
+ include_metadata: MetadataOptions,
1283
1267
  prefetch_relationships: bool,
1284
1268
  fields: dict[str, Any] | None,
1285
1269
  ) -> None:
@@ -1314,6 +1298,7 @@ class NodeManager:
1314
1298
  branch=branch,
1315
1299
  at=at,
1316
1300
  branch_agnostic=branch_agnostic,
1301
+ include_metadata=include_metadata,
1317
1302
  )
1318
1303
  await query.execute(db=db)
1319
1304
  grouped_peer_nodes = query.get_peers_group_by_node()
@@ -1331,8 +1316,7 @@ class NodeManager:
1331
1316
  branch=branch,
1332
1317
  at=at,
1333
1318
  db=db,
1334
- include_owner=include_owner,
1335
- include_source=include_source,
1319
+ include_metadata=include_metadata,
1336
1320
  )
1337
1321
 
1338
1322
  for node in nodes_by_id.values():
@@ -1361,7 +1345,9 @@ class NodeManager:
1361
1345
  node_schema = node.get_schema()
1362
1346
  for rel_schema in node_schema.relationships:
1363
1347
  peer_ids = grouped_peer_nodes.get_peer_ids(
1364
- node_id=node.get_id(), rel_name=rel_schema.get_identifier(), direction=rel_schema.direction
1348
+ node_id=node.get_id(),
1349
+ rel_name=rel_schema.get_identifier(),
1350
+ direction=rel_schema.direction,
1365
1351
  )
1366
1352
  if not peer_ids:
1367
1353
  continue
@@ -1386,8 +1372,27 @@ class NodeManager:
1386
1372
  if rel_schema.cardinality is RelationshipCardinality.ONE and len(rel_peers) > 1:
1387
1373
  raise ValueError("At most, one relationship expected")
1388
1374
 
1375
+ rel_peers_with_metadata: list[PeerWithRelationshipMetadata] = []
1376
+ for peer in rel_peers:
1377
+ peer_id = peer.get_id() if isinstance(peer, Node) else peer
1378
+ metadata_map = grouped_peer_nodes.get_metadata_map(
1379
+ node_id=node.get_id(),
1380
+ rel_name=rel_schema.get_identifier(),
1381
+ direction=rel_schema.direction,
1382
+ peer_id=peer_id,
1383
+ )
1384
+ peer_with_metadata = PeerWithRelationshipMetadata(peer=peer)
1385
+ if not metadata_map:
1386
+ rel_peers_with_metadata.append(peer_with_metadata)
1387
+ continue
1388
+ peer_with_metadata.created_at = metadata_map.get(MetadataOptions.CREATED_AT)
1389
+ peer_with_metadata.created_by = metadata_map.get(MetadataOptions.CREATED_BY)
1390
+ peer_with_metadata.updated_at = metadata_map.get(MetadataOptions.UPDATED_AT)
1391
+ peer_with_metadata.updated_by = metadata_map.get(MetadataOptions.UPDATED_BY)
1392
+ rel_peers_with_metadata.append(peer_with_metadata)
1393
+
1389
1394
  rel_manager.has_fetched_relationships = True
1390
- await rel_manager.update(db=db, data=rel_peers)
1395
+ await rel_manager.update(db=db, data=rel_peers_with_metadata)
1391
1396
 
1392
1397
  @classmethod
1393
1398
  async def delete(
@@ -1397,6 +1402,7 @@ class NodeManager:
1397
1402
  branch: Branch | str | None = None,
1398
1403
  at: Timestamp | None = None,
1399
1404
  cascade_delete: bool = True,
1405
+ user_id: str = SYSTEM_USER_ID,
1400
1406
  ) -> list[Node]:
1401
1407
  """Returns list of deleted nodes because of cascading deletes"""
1402
1408
  branch = await registry.get_branch(branch=branch, db=db)
@@ -1411,7 +1417,7 @@ class NodeManager:
1411
1417
  nodes_to_delete += list(node_map.values())
1412
1418
 
1413
1419
  for node in nodes_to_delete:
1414
- await node.delete(db=db, at=at)
1420
+ await node.delete(db=db, at=at, user_id=user_id)
1415
1421
 
1416
1422
  return nodes_to_delete
1417
1423