industrial-model 0.1.22__tar.gz → 0.1.24__tar.gz

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 (49) hide show
  1. {industrial_model-0.1.22 → industrial_model-0.1.24}/PKG-INFO +1 -1
  2. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/aggregation_mapper.py +7 -1
  3. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/filter_mapper.py +14 -4
  4. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/queries/__init__.py +3 -1
  5. industrial_model-0.1.24/industrial_model/queries/models.py +98 -0
  6. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/statements/__init__.py +8 -3
  7. {industrial_model-0.1.22 → industrial_model-0.1.24}/pyproject.toml +1 -1
  8. {industrial_model-0.1.22 → industrial_model-0.1.24}/uv.lock +1 -1
  9. industrial_model-0.1.22/industrial_model/queries/models.py +0 -33
  10. {industrial_model-0.1.22 → industrial_model-0.1.24}/.gitignore +0 -0
  11. {industrial_model-0.1.22 → industrial_model-0.1.24}/.python-version +0 -0
  12. {industrial_model-0.1.22 → industrial_model-0.1.24}/README.md +0 -0
  13. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/__init__.py +0 -0
  14. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/__init__.py +0 -0
  15. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/models.py +0 -0
  16. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/optimizer.py +0 -0
  17. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/query_mapper.py +0 -0
  18. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/query_result_mapper.py +0 -0
  19. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/search_mapper.py +0 -0
  20. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/sort_mapper.py +0 -0
  21. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/upsert_mapper.py +0 -0
  22. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/utils.py +0 -0
  23. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/cognite_adapters/view_mapper.py +0 -0
  24. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/config.py +0 -0
  25. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/constants.py +0 -0
  26. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/engines/__init__.py +0 -0
  27. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/engines/async_engine.py +0 -0
  28. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/engines/engine.py +0 -0
  29. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/models/__init__.py +0 -0
  30. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/models/base.py +0 -0
  31. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/models/entities.py +0 -0
  32. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/models/schemas.py +0 -0
  33. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/py.typed +0 -0
  34. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/queries/params.py +0 -0
  35. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/statements/expressions.py +0 -0
  36. {industrial_model-0.1.22 → industrial_model-0.1.24}/industrial_model/utils.py +0 -0
  37. {industrial_model-0.1.22 → industrial_model-0.1.24}/scripts/build.sh +0 -0
  38. {industrial_model-0.1.22 → industrial_model-0.1.24}/scripts/format.sh +0 -0
  39. {industrial_model-0.1.22 → industrial_model-0.1.24}/scripts/lint.sh +0 -0
  40. {industrial_model-0.1.22 → industrial_model-0.1.24}/scripts/publish.sh +0 -0
  41. {industrial_model-0.1.22 → industrial_model-0.1.24}/tests/__init__.py +0 -0
  42. {industrial_model-0.1.22 → industrial_model-0.1.24}/tests/cognite-sdk-config.yaml +0 -0
  43. {industrial_model-0.1.22 → industrial_model-0.1.24}/tests/hubs.py +0 -0
  44. {industrial_model-0.1.22 → industrial_model-0.1.24}/tests/models.py +0 -0
  45. {industrial_model-0.1.22 → industrial_model-0.1.24}/tests/test_schema.py +0 -0
  46. {industrial_model-0.1.22 → industrial_model-0.1.24}/tests/tests_adapter.py +0 -0
  47. {industrial_model-0.1.22 → industrial_model-0.1.24}/tests/tests_aggregate.py +0 -0
  48. {industrial_model-0.1.22 → industrial_model-0.1.24}/tests/tests_search.py +0 -0
  49. {industrial_model-0.1.22 → industrial_model-0.1.24}/tests/tests_upsert_mapper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: industrial-model
3
- Version: 0.1.22
3
+ Version: 0.1.24
4
4
  Summary: Industrial Model ORM
5
5
  Author-email: Lucas Alves <lucasrosaalves@gmail.com>
6
6
  Classifier: Programming Language :: Python
@@ -62,10 +62,16 @@ class AggregationMapper:
62
62
 
63
63
  if metric_aggregation is None:
64
64
  raise ValueError(f"Unsupported aggregate function: {statement.aggregate_}")
65
+
66
+ group_by_columns = (
67
+ [prop.property for prop in statement.group_by_properties]
68
+ if statement.group_by_properties is not None
69
+ else statement.entity.get_group_by_fields()
70
+ )
65
71
  return AggregationQuery(
66
72
  view=root_view,
67
73
  metric_aggregation=metric_aggregation,
68
74
  filters=filters_,
69
- group_by_columns=statement.entity.get_group_by_fields(),
75
+ group_by_columns=group_by_columns,
70
76
  limit=statement.limit_,
71
77
  )
@@ -1,9 +1,11 @@
1
1
  from datetime import date, datetime
2
+ from typing import Any
2
3
 
3
4
  import cognite.client.data_classes.filters as cdf_filters
4
5
  from cognite.client.data_classes.data_modeling import MappedProperty, View
5
6
 
6
7
  from industrial_model.cognite_adapters.utils import get_property_ref
8
+ from industrial_model.models.entities import InstanceId
7
9
  from industrial_model.statements import (
8
10
  BoolExpression,
9
11
  Expression,
@@ -54,11 +56,8 @@ class FilterMapper:
54
56
  property_ref = get_property_ref(expression.property, root_view)
55
57
 
56
58
  value_ = expression.value
57
- if isinstance(value_, datetime):
58
- value_ = datetime_to_ms_iso_timestamp(value_)
59
59
 
60
- if isinstance(value_, date):
61
- value_ = value_.strftime("%Y-%m-%d")
60
+ value_ = self._handle_type_value_convertion(value_)
62
61
 
63
62
  if expression.operator == "==":
64
63
  return cdf_filters.Equals(property_ref, value_)
@@ -96,3 +95,14 @@ class FilterMapper:
96
95
  assert isinstance(view_definiton, MappedProperty)
97
96
  assert view_definiton.source
98
97
  return self._view_mapper.get_view(view_definiton.source.external_id)
98
+
99
+ def _handle_type_value_convertion(self, value_: Any) -> Any:
100
+ if isinstance(value_, datetime):
101
+ return datetime_to_ms_iso_timestamp(value_)
102
+ elif isinstance(value_, date):
103
+ return value_.strftime("%Y-%m-%d")
104
+ elif isinstance(value_, InstanceId):
105
+ return value_.model_dump(mode="json", by_alias=True)
106
+ elif isinstance(value_, list):
107
+ return [self._handle_type_value_convertion(v) for v in value_]
108
+ return value_
@@ -1,9 +1,11 @@
1
- from .models import BasePaginatedQuery, BaseQuery
1
+ from .models import BaseAggregationQuery, BasePaginatedQuery, BaseQuery, BaseSearchQuery
2
2
  from .params import NestedQueryParam, QueryParam, SortParam
3
3
 
4
4
  __all__ = [
5
5
  "BaseQuery",
6
6
  "BasePaginatedQuery",
7
+ "BaseSearchQuery",
8
+ "BaseAggregationQuery",
7
9
  "SortParam",
8
10
  "QueryParam",
9
11
  "NestedQueryParam",
@@ -0,0 +1,98 @@
1
+ from typing import Any
2
+
3
+ from industrial_model.models import RootModel, TAggregatedViewInstance, TViewInstance
4
+ from industrial_model.statements import (
5
+ AggregateTypes,
6
+ AggregationStatement,
7
+ SearchStatement,
8
+ Statement,
9
+ aggregate,
10
+ )
11
+
12
+ from .params import NestedQueryParam, QueryParam, SortParam
13
+
14
+
15
+ class BaseQuery(RootModel):
16
+ def to_statement(self, entity: type[TViewInstance]) -> Statement[TViewInstance]:
17
+ statement = Statement(entity)
18
+
19
+ for key, item in self.__class__.model_fields.items():
20
+ values = getattr(self, key)
21
+ if not values:
22
+ continue
23
+ for metadata_item in item.metadata:
24
+ if isinstance(metadata_item, SortParam):
25
+ statement.sort(values, metadata_item.direction)
26
+ elif isinstance(metadata_item, QueryParam | NestedQueryParam):
27
+ statement.where(metadata_item.to_expression(values))
28
+
29
+ return statement
30
+
31
+
32
+ class BasePaginatedQuery(BaseQuery):
33
+ limit: int = 1000
34
+ cursor: str | None = None
35
+
36
+ def to_statement(self, entity: type[TViewInstance]) -> Statement[TViewInstance]:
37
+ statement = super().to_statement(entity)
38
+ statement.limit(self.limit)
39
+ statement.cursor(self.cursor)
40
+
41
+ return statement
42
+
43
+
44
+ class BaseSearchQuery(RootModel):
45
+ query: str | None = None
46
+ query_properties: list[str] | list[Any] | None = None
47
+ limit: int = 1000
48
+
49
+ def to_statement(
50
+ self, entity: type[TViewInstance]
51
+ ) -> SearchStatement[TViewInstance]:
52
+ statement = SearchStatement(entity)
53
+
54
+ for key, item in self.__class__.model_fields.items():
55
+ values = getattr(self, key)
56
+ if not values:
57
+ continue
58
+ for metadata_item in item.metadata:
59
+ if isinstance(metadata_item, SortParam):
60
+ statement.sort(values, metadata_item.direction)
61
+ elif isinstance(metadata_item, QueryParam | NestedQueryParam):
62
+ statement.where(metadata_item.to_expression(values))
63
+ if self.query:
64
+ statement.query_by(self.query, self.query_properties)
65
+ statement.limit(self.limit)
66
+
67
+ return statement
68
+
69
+
70
+ class BaseAggregationQuery(RootModel):
71
+ aggregate: AggregateTypes | None = None
72
+ group_by_properties: list[str] | list[Any] | None = None
73
+ aggregation_property: str | None = None
74
+ limit: int | None = None
75
+
76
+ def to_statement(
77
+ self, entity: type[TAggregatedViewInstance]
78
+ ) -> AggregationStatement[TAggregatedViewInstance]:
79
+ statement = aggregate(entity, self.aggregate)
80
+
81
+ for key, item in self.__class__.model_fields.items():
82
+ values = getattr(self, key)
83
+ if not values:
84
+ continue
85
+ for metadata_item in item.metadata:
86
+ if isinstance(metadata_item, QueryParam | NestedQueryParam):
87
+ statement.where(metadata_item.to_expression(values))
88
+
89
+ if self.group_by_properties:
90
+ statement.group_by(*self.group_by_properties)
91
+
92
+ if self.aggregation_property:
93
+ statement.aggregate_by(self.aggregation_property)
94
+
95
+ if self.limit:
96
+ statement.limit(self.limit)
97
+
98
+ return statement
@@ -74,7 +74,7 @@ class SearchStatement(BaseStatement[T]):
74
74
  def query_by(
75
75
  self,
76
76
  query: str,
77
- query_properties: list[Column | str | Any] | None = None,
77
+ query_properties: list[Column] | list[str] | list[Any] | None = None,
78
78
  ) -> Self:
79
79
  self.query = query
80
80
  self.query_properties = (
@@ -97,10 +97,15 @@ class AggregationStatement(Generic[T]):
97
97
  entity: type[T] = field(init=True)
98
98
  aggregate: AggregateTypes = field(init=True)
99
99
 
100
+ group_by_properties: list[Column] | None = field(init=False, default=None)
100
101
  aggregation_property: Column = field(init=False, default=Column("externalId"))
101
102
  where_clauses: list[Expression] = field(init=False, default_factory=list)
102
103
  limit_: int = field(init=False, default=-1)
103
104
 
105
+ def group_by(self, *property: str | Column | Any) -> Self:
106
+ self.group_by_properties = [_create_column(prop) for prop in property]
107
+ return self
108
+
104
109
  def aggregate_by(self, property: str | Column | Any) -> Self:
105
110
  self.aggregation_property = _create_column(property)
106
111
  return self
@@ -122,9 +127,9 @@ def select(entity: type[T]) -> Statement[T]:
122
127
 
123
128
  def aggregate(
124
129
  entity: type[T],
125
- aggregate: AggregateTypes = "count",
130
+ aggregate: AggregateTypes | None = "count",
126
131
  ) -> AggregationStatement[T]:
127
- return AggregationStatement(entity=entity, aggregate=aggregate)
132
+ return AggregationStatement(entity=entity, aggregate=aggregate or "count")
128
133
 
129
134
 
130
135
  def search(entity: type[T]) -> SearchStatement[T]:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "industrial-model"
3
- version = "0.1.22"
3
+ version = "0.1.24"
4
4
  description = "Industrial Model ORM"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -215,7 +215,7 @@ wheels = [
215
215
 
216
216
  [[package]]
217
217
  name = "industrial-model"
218
- version = "0.1.22"
218
+ version = "0.1.24"
219
219
  source = { editable = "." }
220
220
  dependencies = [
221
221
  { name = "anyio" },
@@ -1,33 +0,0 @@
1
- from industrial_model.models import RootModel, TViewInstance
2
- from industrial_model.statements import Statement
3
-
4
- from .params import NestedQueryParam, QueryParam, SortParam
5
-
6
-
7
- class BaseQuery(RootModel):
8
- def to_statement(self, entity: type[TViewInstance]) -> Statement[TViewInstance]:
9
- statement = Statement(entity)
10
-
11
- for key, item in self.__class__.model_fields.items():
12
- values = getattr(self, key)
13
- if not values:
14
- continue
15
- for metadata_item in item.metadata:
16
- if isinstance(metadata_item, SortParam):
17
- statement.sort(values, metadata_item.direction)
18
- elif isinstance(metadata_item, QueryParam | NestedQueryParam):
19
- statement.where(metadata_item.to_expression(values))
20
-
21
- return statement
22
-
23
-
24
- class BasePaginatedQuery(BaseQuery):
25
- limit: int = 1000
26
- cursor: str | None = None
27
-
28
- def to_statement(self, entity: type[TViewInstance]) -> Statement[TViewInstance]:
29
- statement = super().to_statement(entity)
30
- statement.limit(self.limit)
31
- statement.cursor(self.cursor)
32
-
33
- return statement