industrial-model 0.1.27__py3-none-any.whl → 0.1.29__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.
@@ -1,4 +1,5 @@
1
1
  from abc import abstractmethod
2
+ from datetime import date, datetime
2
3
  from typing import (
3
4
  Any,
4
5
  ClassVar,
@@ -10,6 +11,8 @@ from typing import (
10
11
 
11
12
  from pydantic import PrivateAttr
12
13
 
14
+ from industrial_model.statements import Column
15
+
13
16
  from .base import DBModelMetaclass, RootModel
14
17
 
15
18
 
@@ -45,6 +48,7 @@ class ViewInstanceConfig(TypedDict, total=False):
45
48
  view_external_id: str | None
46
49
  instance_spaces: list[str] | None
47
50
  instance_spaces_prefix: str | None
51
+ view_code: str | None
48
52
 
49
53
 
50
54
  class ViewInstance(InstanceId, metaclass=DBModelMetaclass):
@@ -56,6 +60,54 @@ class ViewInstance(InstanceId, metaclass=DBModelMetaclass):
56
60
  def get_view_external_id(cls) -> str:
57
61
  return cls.view_config.get("view_external_id") or cls.__name__
58
62
 
63
+ def generate_model_id(
64
+ self,
65
+ fields: list[str] | list[Column] | list[Any],
66
+ view_code_as_prefix: bool = True,
67
+ separator: str = "-",
68
+ ) -> str:
69
+ if not fields:
70
+ raise ValueError("Fields list cannot be empty")
71
+ field_values = self._get_field_values(fields)
72
+
73
+ view_code = self.view_config.get("view_code")
74
+
75
+ result = separator.join(field_values)
76
+ return (
77
+ f"{view_code}{separator}{result}"
78
+ if view_code_as_prefix and view_code
79
+ else result
80
+ )
81
+
82
+ def _get_field_values(
83
+ self, fields: list[str] | list[Column] | list[Any]
84
+ ) -> list[str]:
85
+ field_values: list[str] = []
86
+ for field in fields:
87
+ if not isinstance(field, str | Column):
88
+ field_type = type(field).__name__
89
+ raise TypeError(
90
+ f"Expected field to be a string or Column, got {field_type}"
91
+ )
92
+ field_name = self.get_field_name(
93
+ field.property if isinstance(field, Column) else field
94
+ )
95
+ if field_name is None:
96
+ raise ValueError(f"Field {field} not found in the model")
97
+ field_entry = getattr(self, field_name)
98
+
99
+ field_entry_str = ""
100
+ if isinstance(field_entry, str):
101
+ field_entry_str = field_entry
102
+ elif isinstance(field_entry, date | datetime):
103
+ field_entry_str = field_entry.isoformat()
104
+ elif isinstance(field_entry, InstanceId):
105
+ field_entry_str = field_entry.external_id
106
+ else:
107
+ field_entry_str = str(field_entry)
108
+ field_values.append(field_entry_str.replace(" ", ""))
109
+ return field_values
110
+
59
111
 
60
112
  class WritableViewInstance(ViewInstance):
61
113
  @abstractmethod
@@ -1,5 +1,5 @@
1
1
  from .models import BaseAggregationQuery, BasePaginatedQuery, BaseQuery, BaseSearchQuery
2
- from .params import NestedQueryParam, QueryParam, SortParam
2
+ from .params import BoolQueryParam, NestedQueryParam, QueryParam, SortParam
3
3
 
4
4
  __all__ = [
5
5
  "BaseQuery",
@@ -9,4 +9,5 @@ __all__ = [
9
9
  "SortParam",
10
10
  "QueryParam",
11
11
  "NestedQueryParam",
12
+ "BoolQueryParam",
12
13
  ]
@@ -7,24 +7,17 @@ from industrial_model.statements import (
7
7
  SearchStatement,
8
8
  Statement,
9
9
  aggregate,
10
+ search,
11
+ select,
10
12
  )
11
13
 
12
- from .params import NestedQueryParam, QueryParam, SortParam
14
+ from .utils import extract_base_statement_params
13
15
 
14
16
 
15
17
  class BaseQuery(RootModel):
16
18
  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 values is None:
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))
19
+ statement = select(entity)
20
+ _set_base_statement_params(self, statement)
28
21
 
29
22
  return statement
30
23
 
@@ -49,17 +42,8 @@ class BaseSearchQuery(RootModel):
49
42
  def to_statement(
50
43
  self, entity: type[TViewInstance]
51
44
  ) -> SearchStatement[TViewInstance]:
52
- statement = SearchStatement(entity)
53
-
54
- for key, item in self.__class__.model_fields.items():
55
- values = getattr(self, key)
56
- if values is None:
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))
45
+ statement = search(entity)
46
+ _set_base_statement_params(self, statement)
63
47
  if self.query:
64
48
  statement.query_by(self.query, self.query_properties)
65
49
  statement.limit(self.limit)
@@ -78,13 +62,7 @@ class BaseAggregationQuery(RootModel):
78
62
  ) -> AggregationStatement[TAggregatedViewInstance]:
79
63
  statement = aggregate(entity, self.aggregate)
80
64
 
81
- for key, item in self.__class__.model_fields.items():
82
- values = getattr(self, key)
83
- if values is None:
84
- continue
85
- for metadata_item in item.metadata:
86
- if isinstance(metadata_item, QueryParam | NestedQueryParam):
87
- statement.where(metadata_item.to_expression(values))
65
+ _set_base_statement_params(self, statement)
88
66
 
89
67
  if self.group_by_properties:
90
68
  statement.group_by(*self.group_by_properties)
@@ -96,3 +74,19 @@ class BaseAggregationQuery(RootModel):
96
74
  statement.limit(self.limit)
97
75
 
98
76
  return statement
77
+
78
+
79
+ def _set_base_statement_params(
80
+ entity: RootModel,
81
+ statement: Statement[TViewInstance]
82
+ | SearchStatement[TViewInstance]
83
+ | AggregationStatement[TAggregatedViewInstance],
84
+ ) -> None:
85
+ filters_, sort_params = extract_base_statement_params(entity)
86
+ statement.where(*filters_)
87
+
88
+ if isinstance(statement, AggregationStatement):
89
+ return
90
+
91
+ for sort_value, direction in sort_params:
92
+ statement.sort(sort_value, direction)
@@ -2,6 +2,7 @@ from dataclasses import dataclass
2
2
  from typing import Any
3
3
 
4
4
  from industrial_model.constants import (
5
+ BOOL_EXPRESSION_OPERATORS,
5
6
  LEAF_EXPRESSION_OPERATORS,
6
7
  SORT_DIRECTION,
7
8
  )
@@ -49,6 +50,17 @@ class NestedQueryParam:
49
50
  )
50
51
 
51
52
 
53
+ @dataclass
54
+ class BoolQueryParam:
55
+ operator: BOOL_EXPRESSION_OPERATORS
56
+
57
+ def to_expression(self, filters: list[Expression]) -> Expression:
58
+ return BoolExpression(
59
+ operator=self.operator,
60
+ filters=filters,
61
+ )
62
+
63
+
52
64
  @dataclass
53
65
  class SortParam:
54
66
  direction: SORT_DIRECTION
@@ -0,0 +1,42 @@
1
+ from typing import Any
2
+
3
+ from industrial_model.constants import SORT_DIRECTION
4
+ from industrial_model.models import RootModel
5
+ from industrial_model.statements import Expression
6
+
7
+ from .params import BoolQueryParam, NestedQueryParam, QueryParam, SortParam
8
+
9
+
10
+ def extract_base_statement_params(
11
+ entity: RootModel,
12
+ ) -> tuple[list[Expression], list[tuple[Any, SORT_DIRECTION]]]:
13
+ filters_: list[Expression] = []
14
+ sort_params: list[tuple[Any, SORT_DIRECTION]] = []
15
+
16
+ for key, item in entity.__class__.model_fields.items():
17
+ values = getattr(entity, key)
18
+ if values is None:
19
+ continue
20
+ for metadata_item in item.metadata:
21
+ if isinstance(metadata_item, SortParam):
22
+ sort_params.append((values, metadata_item.direction))
23
+ elif isinstance(
24
+ metadata_item, QueryParam | NestedQueryParam | BoolQueryParam
25
+ ):
26
+ filter_ = _extract_expression(metadata_item, values)
27
+ if filter_ is not None:
28
+ filters_.append(filter_)
29
+ return filters_, sort_params
30
+
31
+
32
+ def _extract_expression(
33
+ metadata_item: QueryParam | NestedQueryParam | BoolQueryParam, values: Any
34
+ ) -> Expression | None:
35
+ if isinstance(metadata_item, QueryParam | NestedQueryParam):
36
+ return metadata_item.to_expression(values)
37
+
38
+ if not isinstance(values, RootModel):
39
+ return None
40
+
41
+ filters_, _ = extract_base_statement_params(values)
42
+ return metadata_item.to_expression(filters_)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: industrial-model
3
- Version: 0.1.27
3
+ Version: 0.1.29
4
4
  Summary: Industrial Model ORM
5
5
  Author-email: Lucas Alves <lucasrosaalves@gmail.com>
6
6
  Classifier: Programming Language :: Python
@@ -20,13 +20,14 @@ industrial_model/engines/async_engine.py,sha256=-sQv2vn93bBmTZOxY_C1r40YP7IMl1ND
20
20
  industrial_model/engines/engine.py,sha256=lECOpjN6fGvKt28b441isT_u4UNF3LeLiJH-zwHmkYw,3798
21
21
  industrial_model/models/__init__.py,sha256=AzJ0CyPK5PvUCX45FFtybl13tkukUvk2UAF_90s_LQ8,742
22
22
  industrial_model/models/base.py,sha256=iGhDjXqA5ULEQIFHtkMi7WYJl0nQq1wi8_zqOr-Ep78,1649
23
- industrial_model/models/entities.py,sha256=tHOFjS-9XsaXVrZ-x0tZR1DWL2Cc8MHe82qsIazqmnM,2811
23
+ industrial_model/models/entities.py,sha256=BC85P8THwvVmcNpYq2spJuFJtlK8Oegkmd0kx3CI_wU,4704
24
24
  industrial_model/models/schemas.py,sha256=EoLK9GYdS-0DQ98myTP3wOU9YpWIJOfDSLOYZUy3xEY,4559
25
- industrial_model/queries/__init__.py,sha256=0cF-KTTGHLhdFKe3T_5cEVHsTN95iAV7R6FUutvuoaU,317
26
- industrial_model/queries/models.py,sha256=XS-50Ja11fVM5G7XTvrFf4OSUD3QO58rAKkkFBQ3Xbg,3255
27
- industrial_model/queries/params.py,sha256=U2LCdmDs_jrROvJIsWdopAmZAhXrK2gDr4kuDlVK7Ug,1384
25
+ industrial_model/queries/__init__.py,sha256=lA83zOxMRgBgkseWJgK9kCr1vD8D8iSWs9NGGRnoYKk,355
26
+ industrial_model/queries/models.py,sha256=VK69c4L0b0miPrKvOQBB8A01SPxZXYThrquv6gw5OGY,2544
27
+ industrial_model/queries/params.py,sha256=50qY5BO5onLsXorhcv-7qCKhJaMO94UzhKLCmZKY55s,1667
28
+ industrial_model/queries/utils.py,sha256=uP6PLh9IVHDK6J8x444zHWPmyV4PkxdLO-PMc6qWItc,1505
28
29
  industrial_model/statements/__init__.py,sha256=rjLRo2KoazHQaOpmPkxbI3_Nm8NCkJxjpuqow6IZVSc,4221
29
30
  industrial_model/statements/expressions.py,sha256=4ZZOcZroI5-4xRw4PXIRlufi0ARndE5zSbbxLDpR2Ec,4816
30
- industrial_model-0.1.27.dist-info/METADATA,sha256=6Y23wxqT9bOGAos8ivWJTLH3Renj_fxrB1ZxZiR_JCQ,6858
31
- industrial_model-0.1.27.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
32
- industrial_model-0.1.27.dist-info/RECORD,,
31
+ industrial_model-0.1.29.dist-info/METADATA,sha256=vNGyeERDw-3hlRpxgxKjGERKp8VhwNPBhYRzoqWlArA,6858
32
+ industrial_model-0.1.29.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
33
+ industrial_model-0.1.29.dist-info/RECORD,,