industrial-model 1.0.0__py3-none-any.whl → 1.1.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.
@@ -124,20 +124,29 @@ class CogniteAdapter:
124
124
  return data
125
125
 
126
126
  def upsert(
127
- self, entries: list[TWritableViewInstance], replace: bool = False
127
+ self,
128
+ entries: list[TWritableViewInstance],
129
+ replace: bool = False,
130
+ remove_unset: bool = False,
128
131
  ) -> None:
129
132
  logger = logging.getLogger(__name__)
130
- operation = self._upsert_mapper.map(entries)
133
+ operation = self._upsert_mapper.map(entries, remove_unset)
131
134
 
132
135
  for node_chunk in operation.chunk_nodes():
133
- logger.debug(f"Upserting {len(node_chunk)} nodes (replace={replace})")
136
+ logger.debug(
137
+ f"Upserting {len(node_chunk)} nodes (replace={replace}, "
138
+ "remove_unset={remove_unset})"
139
+ )
134
140
  self._cognite_client.data_modeling.instances.apply(
135
141
  nodes=node_chunk,
136
142
  replace=replace,
137
143
  )
138
144
 
139
145
  for edge_chunk in operation.chunk_edges():
140
- logger.debug(f"Upserting {len(edge_chunk)} edges (replace={replace})")
146
+ logger.debug(
147
+ f"Upserting {len(edge_chunk)} edges (replace={replace},"
148
+ "remove_unset={remove_unset})"
149
+ )
141
150
  self._cognite_client.data_modeling.instances.apply(
142
151
  edges=edge_chunk,
143
152
  replace=replace,
@@ -1,4 +1,4 @@
1
- from cognite.client.data_classes.data_modeling import InstanceSort, View
1
+ from cognite.client.data_classes.data_modeling import InstanceSort, MappedProperty, View
2
2
 
3
3
  from industrial_model.cognite_adapters.utils import get_property_ref
4
4
  from industrial_model.constants import SORT_DIRECTION
@@ -15,7 +15,17 @@ class SortMapper:
15
15
  InstanceSort(
16
16
  property=get_property_ref(column.property, root_view),
17
17
  direction=direction,
18
- nulls_first=direction == "descending",
18
+ nulls_first=self._is_nulls_first(column, root_view, direction),
19
19
  )
20
20
  for column, direction in sort_clauses
21
21
  ]
22
+
23
+ def _is_nulls_first(
24
+ self, column: Column, root_view: View, direction: SORT_DIRECTION
25
+ ) -> bool:
26
+ view_property = root_view.properties.get(column.property)
27
+
28
+ if isinstance(view_property, MappedProperty) and view_property.source:
29
+ return direction == "ascending"
30
+
31
+ return direction == "descending"
@@ -25,14 +25,16 @@ class UpsertMapper:
25
25
  def __init__(self, view_mapper: ViewMapper):
26
26
  self._view_mapper = view_mapper
27
27
 
28
- def map(self, instances: list[TWritableViewInstance]) -> UpsertOperation:
28
+ def map(
29
+ self, instances: list[TWritableViewInstance], remove_unset: bool
30
+ ) -> UpsertOperation:
29
31
  nodes: dict[tuple[str, str], NodeApply] = {}
30
32
  edges: dict[tuple[str, str], EdgeApply] = {}
31
33
  edges_to_delete: dict[tuple[str, str], EdgeContainer] = {}
32
34
 
33
35
  for instance in instances:
34
36
  entry_nodes, entry_edges, entry_edges_to_delete = self._map_instance(
35
- instance
37
+ instance, remove_unset
36
38
  )
37
39
 
38
40
  nodes[instance.as_tuple()] = entry_nodes
@@ -48,7 +50,7 @@ class UpsertMapper:
48
50
  )
49
51
 
50
52
  def _map_instance(
51
- self, instance: TWritableViewInstance
53
+ self, instance: TWritableViewInstance, remove_unset: bool
52
54
  ) -> tuple[NodeApply, list[EdgeApply], list[EdgeContainer]]:
53
55
  view = self._view_mapper.get_view(instance.get_view_external_id())
54
56
 
@@ -59,6 +61,10 @@ class UpsertMapper:
59
61
  property_key = instance.get_field_name(property_name)
60
62
  if not property_key:
61
63
  continue
64
+
65
+ if remove_unset and property_key not in instance.model_fields_set:
66
+ continue
67
+
62
68
  entry = instance.__getattribute__(property_key)
63
69
 
64
70
  if isinstance(property, MappedProperty):
@@ -20,13 +20,13 @@ def generate_engine_params(
20
20
  file_env_parsed = env_sub_template.substitute(dict(os.environ))
21
21
 
22
22
  engine_config = yaml.safe_load(file_env_parsed)
23
- assert isinstance(
24
- engine_config, dict
25
- ), "Configuration file must contain a dictionary"
23
+ assert isinstance(engine_config, dict), (
24
+ "Configuration file must contain a dictionary"
25
+ )
26
26
  assert "cognite" in engine_config, "Configuration must contain 'cognite' section"
27
- assert (
28
- "data_model" in engine_config
29
- ), "Configuration must contain 'data_model' section"
27
+ assert "data_model" in engine_config, (
28
+ "Configuration must contain 'data_model' section"
29
+ )
30
30
 
31
31
  client = CogniteClient.load(engine_config["cognite"])
32
32
  dm_id = DataModelId.model_validate(engine_config["data_model"])
@@ -55,9 +55,12 @@ class AsyncEngine:
55
55
  return await self._engine.aggregate_async(statement)
56
56
 
57
57
  async def upsert_async(
58
- self, entries: list[TWritableViewInstance], replace: bool = False
58
+ self,
59
+ entries: list[TWritableViewInstance],
60
+ replace: bool = False,
61
+ remove_unset: bool = False,
59
62
  ) -> None:
60
- return await self._engine.upsert_async(entries, replace)
63
+ return await self._engine.upsert_async(entries, replace, remove_unset)
61
64
 
62
65
  async def delete_async(self, nodes: list[TViewInstance]) -> None:
63
66
  return await self._engine.delete_async(nodes)
@@ -98,17 +98,23 @@ class Engine:
98
98
  return await run_async(self.aggregate, statement)
99
99
 
100
100
  def upsert(
101
- self, entries: list[TWritableViewInstance], replace: bool = False
101
+ self,
102
+ entries: list[TWritableViewInstance],
103
+ replace: bool = False,
104
+ remove_unset: bool = False,
102
105
  ) -> None:
103
106
  if not entries:
104
107
  return
105
108
 
106
- return self._cognite_adapter.upsert(entries, replace)
109
+ return self._cognite_adapter.upsert(entries, replace, remove_unset)
107
110
 
108
111
  async def upsert_async(
109
- self, entries: list[TWritableViewInstance], replace: bool = False
112
+ self,
113
+ entries: list[TWritableViewInstance],
114
+ replace: bool = False,
115
+ remove_unset: bool = False,
110
116
  ) -> None:
111
- return await run_async(self.upsert, entries, replace)
117
+ return await run_async(self.upsert, entries, replace, remove_unset)
112
118
 
113
119
  def delete(self, nodes: list[TViewInstance]) -> None:
114
120
  self._cognite_adapter.delete(
@@ -73,9 +73,9 @@ class ViewInstance(InstanceId):
73
73
  return cls.view_config.get("view_external_id") or cls.__name__
74
74
 
75
75
  def get_edge_metadata(self, property: Column | str | Any) -> list[EdgeContainer]:
76
- assert isinstance(
77
- property, Column | str
78
- ), f"Expected property to be Column, or str, got {type(property).__name__}"
76
+ assert isinstance(property, Column | str), (
77
+ f"Expected property to be Column, or str, got {type(property).__name__}"
78
+ )
79
79
  identifier = property.property if isinstance(property, Column) else property
80
80
 
81
81
  edge_map_key = self.get_field_alias(identifier) or self.get_field_name(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: industrial-model
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Industrial Model ORM
5
5
  Project-URL: Homepage, https://github.com/lucasrosaalves/industrial-model
6
6
  Project-URL: Source, https://github.com/lucasrosaalves/industrial-model
@@ -309,7 +309,7 @@ instances = engine.query_all_pages(
309
309
  for instance in instances:
310
310
  instance.aliases.append("new_alias")
311
311
 
312
- engine.upsert(instances, replace=False)
312
+ engine.upsert(instances, replace=False, remove_unset=False)
313
313
  ```
314
314
 
315
315
  ---
@@ -3,7 +3,7 @@ industrial_model/config.py,sha256=fiwW-54fgCBY6ciFlRqeCBCNUvY41D-xuv8rCH7Ok54,29
3
3
  industrial_model/constants.py,sha256=MO85Wk05LHrpfbS4zml1hneJNFxht2oa3KFAKXw92qo,450
4
4
  industrial_model/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  industrial_model/utils.py,sha256=oh4AxwxXaWgIC2uolkCbvkgo0ququHB6yAPVIXy45Ts,663
6
- industrial_model/cognite_adapters/__init__.py,sha256=HPCvjvHO4xKyWxDIK_v7wrFJeQsnmJ84ptTzDQTZoH4,6275
6
+ industrial_model/cognite_adapters/__init__.py,sha256=y8vCi2HdjDDkjqPt9y9LTpWu4ZFtc-65re70aHmc-ho,6497
7
7
  industrial_model/cognite_adapters/aggregation_mapper.py,sha256=CYbOR7Eh447PEwCtPKFCHYh3-K6akwLTJdQ-oeSYvKo,2599
8
8
  industrial_model/cognite_adapters/filter_mapper.py,sha256=eSrEYdEKZHQuJ98gblBYy1qCe5VYpq3fjLSUg8614fk,5261
9
9
  industrial_model/cognite_adapters/models.py,sha256=2j2IS01uPkQEp9WdVk8seYzEqGcDdWFnpzXhusHB2zk,945
@@ -11,17 +11,17 @@ industrial_model/cognite_adapters/optimizer.py,sha256=-iorsO-yOe8wuMNBMsV1KjAmC3
11
11
  industrial_model/cognite_adapters/query_mapper.py,sha256=tpRdrEW6i0NKy5h6bYrIIP96nanPSokK-s5-1d0PES8,6597
12
12
  industrial_model/cognite_adapters/query_result_mapper.py,sha256=KaBqYr5l1t8sQMxEoX_F3J2prypKIPaDJxSzGF_fMB8,10203
13
13
  industrial_model/cognite_adapters/search_mapper.py,sha256=zRe5FgucTWHX2VVbh3iLmzM7FmUAFhJG5t42gXnnJrE,1587
14
- industrial_model/cognite_adapters/sort_mapper.py,sha256=RJUAYlZGXoYzK0PwX63cibRF_L-MUq9g2ZsC2EeNIF4,696
15
- industrial_model/cognite_adapters/upsert_mapper.py,sha256=jzelnmECFcuVkQY7dgZG-xL19yD9kxtYvx827InIMO8,4951
14
+ industrial_model/cognite_adapters/sort_mapper.py,sha256=EQ2Xpfdet8jN6EK0rEZ3IA8L7sPXWVX1MA9kQg4LdXs,1083
15
+ industrial_model/cognite_adapters/upsert_mapper.py,sha256=iHt3gOEruFkZmg7KdynVPdRA7VZbuKhjAST0uFPb5rM,5125
16
16
  industrial_model/cognite_adapters/utils.py,sha256=-9NUG84r49cKvmmzoUinxNF1zhHIlmoWFypUCD_WTeM,4800
17
17
  industrial_model/cognite_adapters/view_mapper.py,sha256=9nWx0P7h8TMthLcOF5GZ4yC4UOndVuUo_s-Oz5nSAyM,1276
18
18
  industrial_model/engines/__init__.py,sha256=7aGHrUm2MxIq39vR8h0xu3i1zNOuT9H9U-q4lV3nErQ,102
19
- industrial_model/engines/_internal.py,sha256=bepUTKygYNHcOB810-KoWIKnzf4hFpwXZoWYJyuOUfc,1090
20
- industrial_model/engines/async_engine.py,sha256=BSuI1vjUsjHeYSvxZM4bK2cEw-WutzjlCUFU0Nnu2-M,2139
21
- industrial_model/engines/engine.py,sha256=icpYh-zgzMM_jsV5AytXoXz-nb2nYKug6qkekeMAQQw,4621
19
+ industrial_model/engines/_internal.py,sha256=a3fdqqP3pVTPkfYIF5W_bNSQiIps3MA4xiGC3HOIYhI,1092
20
+ industrial_model/engines/async_engine.py,sha256=3DXKGQ4spsmG8D3EhCKDCoDL4E2S3TocFIGV2gKF-DI,2206
21
+ industrial_model/engines/engine.py,sha256=l6prJdvWy22nmMsu08VeT9qU18uLK6EFKopEzFdtWag,4755
22
22
  industrial_model/models/__init__.py,sha256=g8oa95iG6c22A-vTYhiZKSYa6RG2C7Ht1dpn5_HfXxs,796
23
23
  industrial_model/models/base.py,sha256=qi44m0KW9KuXKTSJqSLea1poErBeAqm6Hv08VdRYHkU,2023
24
- industrial_model/models/entities.py,sha256=jqTgyCv8frzovKCKg6yVUNO9hoBqz_b3HGYbGwIq7gI,5698
24
+ industrial_model/models/entities.py,sha256=-Jf7bNCijbS3_wZohlog3bRsAkXvkUeAQW9DamJqGFo,5700
25
25
  industrial_model/models/schemas.py,sha256=EoLK9GYdS-0DQ98myTP3wOU9YpWIJOfDSLOYZUy3xEY,4559
26
26
  industrial_model/models/utils.py,sha256=MFS8OyCfh4cYPY_R66-mUaCauQfQy0vd558Rw0tiGDc,1786
27
27
  industrial_model/queries/__init__.py,sha256=lA83zOxMRgBgkseWJgK9kCr1vD8D8iSWs9NGGRnoYKk,355
@@ -30,7 +30,7 @@ industrial_model/queries/params.py,sha256=50qY5BO5onLsXorhcv-7qCKhJaMO94UzhKLCmZ
30
30
  industrial_model/queries/utils.py,sha256=uP6PLh9IVHDK6J8x444zHWPmyV4PkxdLO-PMc6qWItc,1505
31
31
  industrial_model/statements/__init__.py,sha256=3Et9PM7AMbIS7Fh9051Q0u3qUpX6588d1yuNrvdd4wI,5429
32
32
  industrial_model/statements/expressions.py,sha256=4ZZOcZroI5-4xRw4PXIRlufi0ARndE5zSbbxLDpR2Ec,4816
33
- industrial_model-1.0.0.dist-info/METADATA,sha256=NDEiaElRHaf8EmCWcPkT1JUeRVL0xa_ZehEdR0m4iUI,7680
34
- industrial_model-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
35
- industrial_model-1.0.0.dist-info/licenses/LICENSE,sha256=BCHCZ1Qo7m4YvAEIQqtVBI3NebFJdZ8_7m_cxInIlN0,4934
36
- industrial_model-1.0.0.dist-info/RECORD,,
33
+ industrial_model-1.1.0.dist-info/METADATA,sha256=_kqHVSleX7wZ44wqZoRF0ahHdzRU-8xRG_fA5VXZrvg,7700
34
+ industrial_model-1.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
35
+ industrial_model-1.1.0.dist-info/licenses/LICENSE,sha256=BCHCZ1Qo7m4YvAEIQqtVBI3NebFJdZ8_7m_cxInIlN0,4934
36
+ industrial_model-1.1.0.dist-info/RECORD,,