ormlambda 2.8.0__py3-none-any.whl → 2.9.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.
- ormlambda/__init__.py +18 -9
- ormlambda/common/abstract_classes/abstract_model.py +16 -17
- ormlambda/common/abstract_classes/decomposition_query.py +23 -0
- ormlambda/common/interfaces/IStatements.py +37 -30
- ormlambda/databases/my_sql/clauses/insert.py +24 -12
- ormlambda/databases/my_sql/clauses/order.py +31 -17
- ormlambda/databases/my_sql/clauses/select.py +8 -4
- ormlambda/databases/my_sql/clauses/update.py +11 -17
- ormlambda/databases/my_sql/repository.py +56 -6
- ormlambda/databases/my_sql/statements.py +26 -18
- ormlambda/utils/column.py +52 -13
- ormlambda/utils/dtypes.py +4 -12
- ormlambda/utils/fields.py +60 -0
- ormlambda/utils/table_constructor.py +67 -95
- {ormlambda-2.8.0.dist-info → ormlambda-2.9.0.dist-info}/METADATA +3 -2
- {ormlambda-2.8.0.dist-info → ormlambda-2.9.0.dist-info}/RECORD +18 -17
- {ormlambda-2.8.0.dist-info → ormlambda-2.9.0.dist-info}/LICENSE +0 -0
- {ormlambda-2.8.0.dist-info → ormlambda-2.9.0.dist-info}/WHEEL +0 -0
ormlambda/__init__.py
CHANGED
@@ -1,11 +1,20 @@
|
|
1
|
-
# enums
|
2
|
-
from .common.enums import (
|
3
|
-
JoinType,
|
4
|
-
ConditionType,
|
1
|
+
# region enums
|
2
|
+
from .common.enums import (
|
3
|
+
JoinType as JoinType,
|
4
|
+
ConditionType as ConditionType,
|
5
5
|
)
|
6
|
+
from ormlambda.common.interfaces.IStatements import OrderType as OrderType
|
7
|
+
# endregion
|
6
8
|
|
7
|
-
from .common.abstract_classes import AbstractSQLStatements
|
8
|
-
from .common.interfaces import IRepositoryBase
|
9
|
-
from .utils import
|
10
|
-
|
11
|
-
|
9
|
+
from .common.abstract_classes import AbstractSQLStatements as AbstractSQLStatements
|
10
|
+
from .common.interfaces import IRepositoryBase as IRepositoryBase
|
11
|
+
from .utils import (
|
12
|
+
Table as Table,
|
13
|
+
Column as Column,
|
14
|
+
ForeignKey as ForeignKey,
|
15
|
+
)
|
16
|
+
from .utils.lambda_disassembler import (
|
17
|
+
Disassembler as Disassembler,
|
18
|
+
nameof as nameof,
|
19
|
+
)
|
20
|
+
from .model_base import BaseModel as BaseModel # COMMENT: to avoid relative import we need to import BaseModel after import Table,Column, ForeignKey, IRepositoryBase and Disassembler
|
@@ -10,7 +10,6 @@ from ormlambda.common.interfaces.IAggregate import IAggregate
|
|
10
10
|
|
11
11
|
if TYPE_CHECKING:
|
12
12
|
from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase
|
13
|
-
from ormlambda.components.select import ISelect
|
14
13
|
from ormlambda.common.abstract_classes.decomposition_query import ClauseInfo
|
15
14
|
|
16
15
|
|
@@ -46,11 +45,11 @@ class AbstractSQLStatements[T: Table, TRepo](IStatements_two_generic[T, TRepo]):
|
|
46
45
|
@override
|
47
46
|
def repository(self) -> IRepositoryBase[TRepo]: ...
|
48
47
|
|
49
|
-
def _return_flavour[TValue](self, query, flavour: Type[TValue]) -> tuple[TValue]:
|
50
|
-
return self._repository.read_sql(query, flavour=flavour)
|
48
|
+
def _return_flavour[TValue](self, query, flavour: Type[TValue], select) -> tuple[TValue]:
|
49
|
+
return self._repository.read_sql(query, flavour=flavour, model=self._model, select=select)
|
51
50
|
|
52
|
-
def _return_model(self, select
|
53
|
-
response_sql = self._repository.read_sql(query, flavour=dict) # store all columns of the SQL query
|
51
|
+
def _return_model(self, select, query: str):
|
52
|
+
response_sql = self._repository.read_sql(query, flavour=dict, model=self._model, select=select) # store all columns of the SQL query
|
54
53
|
|
55
54
|
if isinstance(response_sql, Iterable):
|
56
55
|
return ClusterQuery[T](select, response_sql).clean_response()
|
@@ -66,7 +65,16 @@ class ClusterQuery[T]:
|
|
66
65
|
self._select: DecompositionQueryBase[T] = select
|
67
66
|
self._response_sql: tuple[dict[str, Any]] = response_sql
|
68
67
|
|
69
|
-
def
|
68
|
+
def clean_response(self) -> tuple[dict[Type[Table], tuple[Table]]]:
|
69
|
+
tbl_dicc: dict[Type[Table], list[Table]] = self.__loop_foo()
|
70
|
+
|
71
|
+
# it not depend of flavour attr
|
72
|
+
for key, val in tbl_dicc.items():
|
73
|
+
tbl_dicc[key] = tuple(val)
|
74
|
+
|
75
|
+
return tuple(tbl_dicc.values())
|
76
|
+
|
77
|
+
def __loop_foo(self) -> dict[Type[Table], list[Table]]:
|
70
78
|
# We must ensure to get the valid attributes for each instance
|
71
79
|
table_initialize = defaultdict(list)
|
72
80
|
|
@@ -75,7 +83,7 @@ class ClusterQuery[T]:
|
|
75
83
|
valid_attr: dict[str, Any] = {}
|
76
84
|
for clause in clauses:
|
77
85
|
if not hasattr(table, clause.column):
|
78
|
-
agg_methods = self.
|
86
|
+
agg_methods = self.__get_all_aggregate_method(clauses)
|
79
87
|
raise ValueError(f"You cannot use aggregation method like '{agg_methods}' to return model objects. Try specifying 'flavour' attribute as 'dict'.")
|
80
88
|
valid_attr[clause.column] = dicc_cols[clause.alias]
|
81
89
|
|
@@ -83,7 +91,7 @@ class ClusterQuery[T]:
|
|
83
91
|
table_initialize[table].append(table(**valid_attr))
|
84
92
|
return table_initialize
|
85
93
|
|
86
|
-
def
|
94
|
+
def __get_all_aggregate_method(self, clauses: list[ClauseInfo]) -> str:
|
87
95
|
res: set[str] = set()
|
88
96
|
|
89
97
|
for clause in clauses:
|
@@ -91,12 +99,3 @@ class ClusterQuery[T]:
|
|
91
99
|
if isinstance(row, IAggregate):
|
92
100
|
res.add(row.__class__.__name__)
|
93
101
|
return ", ".join(res)
|
94
|
-
|
95
|
-
def clean_response(self) -> tuple[dict[Type[Table], tuple[Table]]]:
|
96
|
-
tbl_dicc: dict[Type[Table], list[Table]] = self.loop_foo()
|
97
|
-
|
98
|
-
# it not depend of flavour attr
|
99
|
-
for key, val in tbl_dicc.items():
|
100
|
-
tbl_dicc[key] = tuple(val)
|
101
|
-
|
102
|
-
return tuple(tbl_dicc.values())
|
@@ -44,6 +44,13 @@ class ClauseInfo[T: tp.Type[Table]]:
|
|
44
44
|
def query(self) -> str:
|
45
45
|
return self._query
|
46
46
|
|
47
|
+
@property
|
48
|
+
def dtype[TProp](self) -> tp.Optional[tp.Type[TProp]]:
|
49
|
+
try:
|
50
|
+
return self._table.get_column(self.column).dtype
|
51
|
+
except ValueError:
|
52
|
+
return None
|
53
|
+
|
47
54
|
def _resolve_column(self, data: ClauseDataType) -> str:
|
48
55
|
if isinstance(data, property):
|
49
56
|
return self._table.__properties_mapped__[data]
|
@@ -73,6 +80,17 @@ class ClauseInfo[T: tp.Type[Table]]:
|
|
73
80
|
|
74
81
|
|
75
82
|
class DecompositionQueryBase[T: tp.Type[Table]](IDecompositionQuery[T]):
|
83
|
+
@tp.overload
|
84
|
+
def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]]) -> None: ...
|
85
|
+
@tp.overload
|
86
|
+
def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]], *, alias: bool = ...) -> None: ...
|
87
|
+
@tp.overload
|
88
|
+
def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]], *, alias: bool = ..., alias_name: tp.Optional[str] = ...) -> None: ...
|
89
|
+
@tp.overload
|
90
|
+
def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]], *, alias: bool = ..., alias_name: tp.Optional[str] = ..., by: JoinType = ...) -> None: ...
|
91
|
+
@tp.overload
|
92
|
+
def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]], *, alias: bool = ..., alias_name: tp.Optional[str] = ..., by: JoinType = ..., replace_asterisk_char: bool = ...) -> None: ...
|
93
|
+
|
76
94
|
def __init__[*Ts](
|
77
95
|
self,
|
78
96
|
table: T,
|
@@ -98,6 +116,11 @@ class DecompositionQueryBase[T: tp.Type[Table]](IDecompositionQuery[T]):
|
|
98
116
|
|
99
117
|
self.__clauses_list_generetor(lambda_query)
|
100
118
|
|
119
|
+
def __getitem__(self, key: str) -> ClauseInfo:
|
120
|
+
for clause in self._all_clauses:
|
121
|
+
if clause.alias == key:
|
122
|
+
return clause
|
123
|
+
|
101
124
|
def alias_children_resolver[Tclause: tp.Type[Table]](self, clause_info: ClauseInfo[Tclause]):
|
102
125
|
DEFAULT_ALIAS: str = f"{clause_info._table.__table_name__}_{clause_info._column}"
|
103
126
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
2
2
|
from typing import Any, Callable, Iterable, Optional, Literal, Type, Union, overload, TYPE_CHECKING, TypeVar
|
3
3
|
from enum import Enum
|
4
4
|
from abc import abstractmethod, ABC
|
5
|
+
import enum
|
5
6
|
|
6
7
|
from .IRepositoryBase import IRepositoryBase
|
7
8
|
from ormlambda.common.enums import JoinType
|
@@ -10,7 +11,15 @@ if TYPE_CHECKING:
|
|
10
11
|
from ormlambda import Table
|
11
12
|
from .IAggregate import IAggregate
|
12
13
|
|
13
|
-
|
14
|
+
|
15
|
+
class OrderType(enum.Enum):
|
16
|
+
ASC = "ASC"
|
17
|
+
DESC = "DESC"
|
18
|
+
|
19
|
+
|
20
|
+
OrderTypeString = Literal["ASC", "DESC"]
|
21
|
+
|
22
|
+
OrderTypes = OrderTypeString | OrderType | Iterable[OrderType]
|
14
23
|
|
15
24
|
# TODOH: This var is duplicated from 'src\ormlambda\databases\my_sql\clauses\create_database.py'
|
16
25
|
TypeExists = Literal["fail", "replace", "append"]
|
@@ -109,7 +118,7 @@ class IStatements[T: Table](ABC):
|
|
109
118
|
@overload
|
110
119
|
def delete(self, instance: list[T]) -> None: ...
|
111
120
|
@abstractmethod
|
112
|
-
def delete(self, instance: Optional[T | list[T]] =
|
121
|
+
def delete(self, instance: Optional[T | list[T]] = ...) -> None: ...
|
113
122
|
|
114
123
|
# endregion
|
115
124
|
# region join
|
@@ -155,9 +164,9 @@ class IStatements[T: Table](ABC):
|
|
155
164
|
@overload
|
156
165
|
def order[TValue](self, _lambda_col: Callable[[T], TValue]) -> IStatements[T]: ...
|
157
166
|
@overload
|
158
|
-
def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type:
|
167
|
+
def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderTypes) -> IStatements[T]: ...
|
159
168
|
@abstractmethod
|
160
|
-
def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type:
|
169
|
+
def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderTypes) -> IStatements[T]: ...
|
161
170
|
|
162
171
|
# endregion
|
163
172
|
# region concat
|
@@ -196,62 +205,60 @@ class IStatements[T: Table](ABC):
|
|
196
205
|
@overload
|
197
206
|
def select(self) -> tuple[T, ...]: ...
|
198
207
|
@overload
|
199
|
-
def select[T1](self, selector: Callable[[T], T1], *, by: Optional[Enum] =
|
208
|
+
def select[T1](self, selector: Callable[[T], T1], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...]]: ...
|
200
209
|
@overload
|
201
|
-
def select[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] =
|
210
|
+
def select[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...]]: ...
|
202
211
|
@overload
|
203
|
-
def select[T1, T2](self, selector: Callable[[T], tuple[T1, T2]], *, by: Optional[Enum] =
|
212
|
+
def select[T1, T2](self, selector: Callable[[T], tuple[T1, T2]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...]]: ...
|
204
213
|
@overload
|
205
|
-
def select[T1, T2, T3](self, selector: Callable[[T], tuple[T1, T2, T3]], *, by: Optional[Enum] =
|
214
|
+
def select[T1, T2, T3](self, selector: Callable[[T], tuple[T1, T2, T3]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...]]: ...
|
206
215
|
@overload
|
207
|
-
def select[T1, T2, T3, T4](self, selector: Callable[[T], tuple[T1, T2, T3, T4]], *, by: Optional[Enum] =
|
216
|
+
def select[T1, T2, T3, T4](self, selector: Callable[[T], tuple[T1, T2, T3, T4]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...]]: ...
|
208
217
|
@overload
|
209
|
-
def select[T1, T2, T3, T4, T5](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5]], *, by: Optional[Enum] =
|
218
|
+
def select[T1, T2, T3, T4, T5](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...]]: ...
|
210
219
|
@overload
|
211
|
-
def select[T1, T2, T3, T4, T5, T6](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6]], *, by: Optional[Enum] =
|
220
|
+
def select[T1, T2, T3, T4, T5, T6](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...]]: ...
|
212
221
|
@overload
|
213
|
-
def select[T1, T2, T3, T4, T5, T6, T7](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7]], *, by: Optional[Enum] =
|
222
|
+
def select[T1, T2, T3, T4, T5, T6, T7](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...]]: ...
|
214
223
|
@overload
|
215
|
-
def select[T1, T2, T3, T4, T5, T6, T7, T8](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8]], *, by: Optional[Enum] =
|
224
|
+
def select[T1, T2, T3, T4, T5, T6, T7, T8](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...]]: ...
|
216
225
|
@overload
|
217
|
-
def select[T1, T2, T3, T4, T5, T6, T7, T8, T9](
|
218
|
-
self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9]], *, by: Optional[Enum] = JoinType.INNER_JOIN
|
219
|
-
) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...], tuple[T9, ...]]: ...
|
226
|
+
def select[T1, T2, T3, T4, T5, T6, T7, T8, T9](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...], tuple[T9, ...]]: ...
|
220
227
|
@overload
|
221
228
|
def select[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](
|
222
|
-
self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]], *, by: Optional[Enum] =
|
229
|
+
self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]], *, by: Optional[Enum] = ...
|
223
230
|
) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...], tuple[T9, ...], tuple[T10, ...]]: ...
|
224
231
|
@overload
|
225
|
-
def select[Ts](self, selector: Optional[Callable[[T], Ts]] =
|
232
|
+
def select[Ts](self, selector: Optional[Callable[[T], Ts]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ...) -> tuple[Ts, ...]: ...
|
226
233
|
@overload
|
227
|
-
def select[Ts](self, selector: Optional[Callable[[T], tuple[Ts]]] =
|
234
|
+
def select[Ts](self, selector: Optional[Callable[[T], tuple[Ts]]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ...) -> tuple[Ts, ...]: ...
|
228
235
|
@overload
|
229
|
-
def select[*Ts](self, selector: Optional[Callable[[T], tuple[*Ts]]] =
|
236
|
+
def select[*Ts](self, selector: Optional[Callable[[T], tuple[*Ts]]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ...) -> tuple[tuple[*Ts]]: ...
|
230
237
|
@overload
|
231
|
-
def select[TFlavour](self, selector: Optional[Callable[[T], tuple]] =
|
238
|
+
def select[TFlavour](self, selector: Optional[Callable[[T], tuple]] = ..., *, flavour: Type[TFlavour], by: Optional[Enum] = ...) -> tuple[TFlavour]: ...
|
232
239
|
@abstractmethod
|
233
|
-
def select[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] =
|
240
|
+
def select[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = ..., *, flavour: Type[TFlavour] = ..., by: JoinType = ...): ...
|
234
241
|
|
235
242
|
# endregion
|
236
243
|
# region select_one
|
237
244
|
@overload
|
238
245
|
def select_one(self) -> T: ...
|
239
246
|
@overload
|
240
|
-
def select_one[TFlavour](self, *, by: Optional[Enum] =
|
247
|
+
def select_one[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour]) -> TFlavour: ...
|
241
248
|
@overload
|
242
|
-
def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] =
|
249
|
+
def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = ...) -> T1: ...
|
243
250
|
@overload
|
244
|
-
def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] =
|
251
|
+
def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = ...) -> tuple[*Ts]: ...
|
245
252
|
@overload
|
246
|
-
def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] =
|
253
|
+
def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type) -> T1: ...
|
247
254
|
@overload
|
248
|
-
def select_one[T1, TFlavour](self, selector: Callable[[T], T1], *, by: Optional[Enum] =
|
255
|
+
def select_one[T1, TFlavour](self, selector: Callable[[T], T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour]) -> T1: ...
|
249
256
|
@overload
|
250
|
-
def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] =
|
257
|
+
def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = ..., flavour: Type[tuple]) -> tuple[*Ts]: ...
|
251
258
|
@overload
|
252
|
-
def select_one[TFlavour](self, selector: Callable[[T], tuple], *, by: Optional[Enum] =
|
259
|
+
def select_one[TFlavour](self, selector: Callable[[T], tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour]) -> TFlavour: ...
|
253
260
|
@abstractmethod
|
254
|
-
def select_one[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = lambda: None, *, flavour: Type[TFlavour] =
|
261
|
+
def select_one[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = lambda: None, *, flavour: Type[TFlavour] = ..., by: Optional[Enum] = ...): ...
|
255
262
|
|
256
263
|
# endregion
|
257
264
|
# region group_by
|
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import
|
1
|
+
from typing import override, Iterable
|
2
2
|
from mysql.connector import MySQLConnection
|
3
3
|
|
4
4
|
from ormlambda import Table
|
@@ -24,13 +24,24 @@ class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase[MySQLConnection]]
|
|
24
24
|
|
25
25
|
@override
|
26
26
|
def insert(self, instances: T | list[T]) -> None:
|
27
|
-
|
28
|
-
self.__fill_dict_list(
|
29
|
-
cols_tuple = new_dict_list[0].keys()
|
30
|
-
join_cols = ", ".join(cols_tuple)
|
31
|
-
unknown_rows = f'({", ".join(["%s"]*len(cols_tuple))})' # The number of "%s" must match the dict 'dicc_0' length
|
27
|
+
valid_cols: list[list[Column]] = []
|
28
|
+
self.__fill_dict_list(valid_cols, instances)
|
32
29
|
|
33
|
-
|
30
|
+
col_names: list[str] = []
|
31
|
+
wildcards: list[str] = []
|
32
|
+
col_values: list[list[str]] = []
|
33
|
+
for i, cols in enumerate(valid_cols):
|
34
|
+
col_values.append([])
|
35
|
+
for col in cols:
|
36
|
+
if i == 0:
|
37
|
+
col_names.append(col.column_name)
|
38
|
+
wildcards.append(col.placeholder)
|
39
|
+
col_values[-1].append(col.column_value_to_query)
|
40
|
+
|
41
|
+
join_cols = ", ".join(col_names)
|
42
|
+
unknown_rows = f'({", ".join(wildcards)})' # The number of "%s" must match the dict 'dicc_0' length
|
43
|
+
|
44
|
+
self._values = [tuple(x) for x in col_values]
|
34
45
|
self._query = f"{self.CLAUSE} {self._model.__table_name__} {f'({join_cols})'} VALUES {unknown_rows}"
|
35
46
|
return None
|
36
47
|
|
@@ -55,17 +66,18 @@ class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase[MySQLConnection]]
|
|
55
66
|
return False
|
56
67
|
return True
|
57
68
|
|
58
|
-
def __fill_dict_list(self, list_dict: list[
|
69
|
+
def __fill_dict_list[TProp](self, list_dict: list[str, TProp], values: T | list[T]) -> list[Column]:
|
59
70
|
if issubclass(values.__class__, Table):
|
60
|
-
|
71
|
+
new_list = []
|
61
72
|
for col in values.__dict__.values():
|
62
73
|
if isinstance(col, Column) and self.__is_valid(col):
|
63
|
-
|
64
|
-
|
65
|
-
|
74
|
+
new_list.append(col)
|
75
|
+
|
76
|
+
list_dict.append(new_list)
|
66
77
|
|
67
78
|
elif isinstance(values, Iterable):
|
68
79
|
for x in values:
|
69
80
|
self.__fill_dict_list(list_dict, x)
|
70
81
|
else:
|
71
82
|
raise Exception(f"Tipo de dato'{type(values)}' no esperado")
|
83
|
+
return None
|
@@ -1,33 +1,47 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from typing import override, Callable, TYPE_CHECKING
|
2
|
+
from typing import override, Callable, TYPE_CHECKING, Any, Iterable
|
3
|
+
|
4
|
+
from ormlambda.common.abstract_classes.decomposition_query import ClauseInfo
|
5
|
+
|
3
6
|
|
4
7
|
if TYPE_CHECKING:
|
5
8
|
from ormlambda import Table
|
6
9
|
|
7
|
-
from ormlambda.
|
8
|
-
from ormlambda.common.interfaces.IQueryCommand import IQuery
|
10
|
+
from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase
|
9
11
|
from ormlambda.common.interfaces.IStatements import OrderType
|
10
12
|
|
11
|
-
ASC = "ASC"
|
12
|
-
DESC = "DESC"
|
13
13
|
|
14
|
-
|
15
|
-
class OrderQuery[T:Table](IQuery):
|
14
|
+
class OrderQuery[T: Table](DecompositionQueryBase[T]):
|
16
15
|
ORDER = "ORDER BY"
|
17
16
|
|
18
|
-
def __init__(self, instance: T,
|
19
|
-
|
20
|
-
|
17
|
+
def __init__[*Ts](self, instance: T, lambda_query: Callable[[Any], tuple[*Ts]], order_type: Iterable[OrderType]) -> None:
|
18
|
+
super().__init__(instance, lambda_query)
|
19
|
+
|
20
|
+
if isinstance(order_type, str) or not isinstance(order_type, Iterable):
|
21
|
+
order_type = (order_type,)
|
21
22
|
|
22
|
-
self.
|
23
|
-
self._order_lambda: Callable[[T], None] = order_lambda
|
24
|
-
self._order_type: str = order_type
|
25
|
-
self._column: str = TreeInstruction(order_lambda).to_list()[0].nested_element.name
|
23
|
+
self._order_type: list[OrderType] = [self.__cast_to_OrderType(x) for x in order_type]
|
26
24
|
|
27
|
-
def
|
28
|
-
|
25
|
+
def __cast_to_OrderType(self, _value: Any) -> Iterable[OrderType]:
|
26
|
+
if isinstance(_value, OrderType):
|
27
|
+
return _value
|
28
|
+
|
29
|
+
if isinstance(_value, str):
|
30
|
+
try:
|
31
|
+
return OrderType(_value)
|
32
|
+
except Exception:
|
33
|
+
pass
|
34
|
+
raise Exception(f"order_type param only can be 'ASC' or 'DESC' string or '{OrderType.__name__}' enum")
|
35
|
+
|
36
|
+
def alias_children_resolver[Tclause](self, clause_info: ClauseInfo[Tclause]):
|
37
|
+
return None
|
29
38
|
|
30
39
|
@override
|
31
40
|
@property
|
32
41
|
def query(self) -> str:
|
33
|
-
|
42
|
+
assert len(self.all_clauses) == len(self._order_type)
|
43
|
+
|
44
|
+
query: list[str] = []
|
45
|
+
for index, x in enumerate(self.all_clauses):
|
46
|
+
query.append(f"{x.query} {self._order_type[index].value}")
|
47
|
+
return f"{self.ORDER} {", ".join(query)}"
|
@@ -3,6 +3,7 @@ from typing import override, Type, Callable, TYPE_CHECKING
|
|
3
3
|
from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase
|
4
4
|
from ormlambda.common.enums.join_type import JoinType
|
5
5
|
from ormlambda.common.interfaces.IAggregate import IAggregate
|
6
|
+
import shapely as shp
|
6
7
|
|
7
8
|
if TYPE_CHECKING:
|
8
9
|
from ormlambda import Table
|
@@ -32,17 +33,20 @@ class Select[T: Type[Table]](DecompositionQueryBase[T]):
|
|
32
33
|
# def alias_children_resolver[Tclause: Type[Table]](self, clause_info: ClauseInfo[Tclause]):
|
33
34
|
# return f"{clause.table.__table_name__}_{name}"
|
34
35
|
|
36
|
+
# TODOL: see who to deal when we will have to add more mysql methods
|
35
37
|
@override
|
36
38
|
@property
|
37
39
|
def query(self) -> str:
|
38
|
-
cols:list[str] = []
|
40
|
+
cols: list[str] = []
|
39
41
|
for x in self.all_clauses:
|
40
|
-
|
42
|
+
if x.dtype is shp.Point:
|
43
|
+
cols.append(x.concat_with_alias(f"ST_AsText({self._table.__table_name__}.{x.column})"))
|
44
|
+
else:
|
45
|
+
cols.append(x.query)
|
41
46
|
|
42
|
-
if isinstance(x._row_column,IAggregate) and x._row_column.has_foreign_keys:
|
47
|
+
if isinstance(x._row_column, IAggregate) and x._row_column.has_foreign_keys:
|
43
48
|
self._fk_relationship.update(x._row_column.fk_relationship)
|
44
49
|
|
45
|
-
|
46
50
|
col: str = ", ".join(cols)
|
47
51
|
query: str = f"{self.CLAUSE} {col} FROM {self._table.__table_name__}"
|
48
52
|
alias = ""
|
@@ -27,26 +27,20 @@ class UpdateQuery[T: Type[Table]](UpdateQueryBase[T, IRepositoryBase[MySQLConnec
|
|
27
27
|
if not isinstance(dicc, dict):
|
28
28
|
raise TypeError
|
29
29
|
|
30
|
-
name_cols: list[
|
30
|
+
name_cols: list[Column] = []
|
31
31
|
|
32
32
|
for col, value in dicc.items():
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
name_cols.append(string_col)
|
41
|
-
self._values.append(value)
|
42
|
-
|
43
|
-
set_query: str = ",".join(["=".join([col, "%s"]) for col in name_cols])
|
33
|
+
col: Column = self._model.get_column(col, value)
|
34
|
+
|
35
|
+
if self.__is_valid__(col):
|
36
|
+
name_cols.append(col)
|
37
|
+
self._values.append(col.column_value_to_query)
|
38
|
+
|
39
|
+
set_query: str = ",".join(["=".join([col.column_name, col.placeholder]) for col in name_cols])
|
44
40
|
|
45
41
|
self._query = f"{self.CLAUSE} {self._model.__table_name__} SET {set_query}"
|
42
|
+
self._values = tuple(self._values)
|
46
43
|
return None
|
47
44
|
|
48
|
-
def __is_valid__(self, col:
|
49
|
-
|
50
|
-
|
51
|
-
column: Column = getattr(instance_table, f"_{col}")
|
52
|
-
return not column.is_auto_generated
|
45
|
+
def __is_valid__(self, col: Column) -> bool:
|
46
|
+
return not col.is_auto_generated
|
@@ -1,7 +1,8 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import Any, Optional, Type, override, Callable
|
3
|
+
from typing import Any, Optional, Type, override, Callable, TYPE_CHECKING
|
4
4
|
import functools
|
5
|
+
import shapely as shp
|
5
6
|
|
6
7
|
# from mysql.connector.pooling import MySQLConnectionPool
|
7
8
|
from mysql.connector import MySQLConnection, Error # noqa: F401
|
@@ -16,12 +17,20 @@ from .clauses import DropDatabase
|
|
16
17
|
from .clauses import DropTable
|
17
18
|
|
18
19
|
|
20
|
+
if TYPE_CHECKING:
|
21
|
+
from src.ormlambda.common.abstract_classes.decomposition_query import ClauseInfo
|
22
|
+
from ormlambda import Table
|
23
|
+
from src.ormlambda.databases.my_sql.clauses.select import Select
|
24
|
+
|
25
|
+
|
19
26
|
class Response[TFlavour, *Ts]:
|
20
|
-
def __init__(self, response_values: list[tuple[*Ts]], columns: tuple[str], flavour: Type[TFlavour], **kwargs) -> None:
|
27
|
+
def __init__(self, response_values: list[tuple[*Ts]], columns: tuple[str], flavour: Type[TFlavour], model: Optional[Table] = None, select: Optional[Select] = None, **kwargs) -> None:
|
21
28
|
self._response_values: list[tuple[*Ts]] = response_values
|
22
29
|
self._columns: tuple[str] = columns
|
23
30
|
self._flavour: Type[TFlavour] = flavour
|
24
31
|
self._kwargs: dict[str, Any] = kwargs
|
32
|
+
self._model: Table = model
|
33
|
+
self._select: Select = select
|
25
34
|
|
26
35
|
self._response_values_index: int = len(self._response_values)
|
27
36
|
# self.select_values()
|
@@ -42,8 +51,10 @@ class Response[TFlavour, *Ts]:
|
|
42
51
|
def response(self) -> tuple[dict[str, tuple[*Ts]]] | tuple[tuple[*Ts]] | tuple[TFlavour]:
|
43
52
|
if not self.is_there_response:
|
44
53
|
return tuple([])
|
45
|
-
|
46
|
-
|
54
|
+
clean_response = self._response_values
|
55
|
+
if self._select is not None:
|
56
|
+
clean_response = self._parser_response()
|
57
|
+
return tuple(self._cast_to_flavour(clean_response))
|
47
58
|
|
48
59
|
def _cast_to_flavour(self, data: list[tuple[*Ts]]) -> list[dict[str, tuple[*Ts]]] | list[tuple[*Ts]] | list[TFlavour]:
|
49
60
|
def _dict() -> list[dict[str, tuple[*Ts]]]:
|
@@ -73,6 +84,38 @@ class Response[TFlavour, *Ts]:
|
|
73
84
|
|
74
85
|
return selector.get(self._flavour, _default)()
|
75
86
|
|
87
|
+
def _parser_response(self) -> TFlavour:
|
88
|
+
new_response: list[list] = []
|
89
|
+
for row in self._response_values:
|
90
|
+
new_row: list = []
|
91
|
+
for i, data in enumerate(row):
|
92
|
+
alias = self._columns[i]
|
93
|
+
clause_info = self._select[alias]
|
94
|
+
if not self._is_parser_required(clause_info):
|
95
|
+
new_row = row
|
96
|
+
break
|
97
|
+
else:
|
98
|
+
parser_data = self.parser_data(clause_info, data)
|
99
|
+
new_row.append(parser_data)
|
100
|
+
if not isinstance(new_row, tuple):
|
101
|
+
new_row = tuple(new_row)
|
102
|
+
|
103
|
+
new_response.append(new_row)
|
104
|
+
return new_response
|
105
|
+
|
106
|
+
@staticmethod
|
107
|
+
def _is_parser_required[T: Table](clause_info: ClauseInfo[T]) -> bool:
|
108
|
+
if clause_info is None:
|
109
|
+
return False
|
110
|
+
|
111
|
+
return clause_info.dtype is shp.Point
|
112
|
+
|
113
|
+
@staticmethod
|
114
|
+
def parser_data[T: Table, TProp](clause_info: ClauseInfo[T], data: TProp):
|
115
|
+
if clause_info.dtype is shp.Point:
|
116
|
+
return shp.from_wkt(data)
|
117
|
+
return data
|
118
|
+
|
76
119
|
|
77
120
|
class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
78
121
|
def get_connection(func: Callable[..., Any]):
|
@@ -107,11 +150,19 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
107
150
|
- flavour: Type[TFlavour]: Useful to return tuple of any Iterable type as dict,set,list...
|
108
151
|
"""
|
109
152
|
|
153
|
+
def get_and_drop_key(key: str) -> Optional[Any]:
|
154
|
+
if key in kwargs:
|
155
|
+
return kwargs.pop(key)
|
156
|
+
return None
|
157
|
+
|
158
|
+
model: Table = get_and_drop_key("model")
|
159
|
+
select: Select = get_and_drop_key("select")
|
160
|
+
|
110
161
|
with cnx.cursor(buffered=True) as cursor:
|
111
162
|
cursor.execute(query)
|
112
163
|
values: list[tuple] = cursor.fetchall()
|
113
164
|
columns: tuple[str] = cursor.column_names
|
114
|
-
return Response[TFlavour](response_values=values, columns=columns, flavour=flavour, **kwargs).response
|
165
|
+
return Response[TFlavour](model=model, response_values=values, columns=columns, flavour=flavour, select=select, **kwargs).response
|
115
166
|
|
116
167
|
# FIXME [ ]: this method does not comply with the implemented interface
|
117
168
|
@get_connection
|
@@ -192,7 +243,6 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
192
243
|
def create_database(self, name: str, if_exists: TypeExists = "fail") -> None:
|
193
244
|
return CreateDatabase(self).execute(name, if_exists)
|
194
245
|
|
195
|
-
|
196
246
|
@property
|
197
247
|
def database(self) -> Optional[str]:
|
198
248
|
return self._data_config.get("database", None)
|
@@ -2,12 +2,12 @@ from __future__ import annotations
|
|
2
2
|
from typing import Iterable, override, Type, TYPE_CHECKING, Any, Callable, Optional
|
3
3
|
import inspect
|
4
4
|
from mysql.connector import MySQLConnection, errors, errorcode
|
5
|
-
|
5
|
+
import functools
|
6
6
|
|
7
7
|
if TYPE_CHECKING:
|
8
8
|
from ormlambda import Table
|
9
9
|
from ormlambda.components.where.abstract_where import AbstractWhere
|
10
|
-
from ormlambda.common.interfaces.IStatements import
|
10
|
+
from ormlambda.common.interfaces.IStatements import OrderTypes
|
11
11
|
from ormlambda.common.interfaces import IQuery, IRepositoryBase, IStatements_two_generic
|
12
12
|
from ormlambda.common.interfaces.IRepositoryBase import TypeExists
|
13
13
|
from ormlambda.common.interfaces import IAggregate
|
@@ -34,6 +34,18 @@ from ormlambda.common.enums import JoinType
|
|
34
34
|
from . import functions as func
|
35
35
|
|
36
36
|
|
37
|
+
# COMMENT: It's so important to prevent information generated by other tests from being retained in the class.
|
38
|
+
def clear_list(f: Callable[..., Any]):
|
39
|
+
@functools.wraps(f)
|
40
|
+
def wrapper(self: MySQLStatements, *args, **kwargs):
|
41
|
+
try:
|
42
|
+
return f(self, *args, **kwargs)
|
43
|
+
finally:
|
44
|
+
self._query_list.clear()
|
45
|
+
|
46
|
+
return wrapper
|
47
|
+
|
48
|
+
|
37
49
|
class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
|
38
50
|
def __init__(self, model: T, repository: IRepositoryBase[MySQLConnection]) -> None:
|
39
51
|
super().__init__(model, repository=repository)
|
@@ -71,11 +83,11 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
|
|
71
83
|
return self._repository.table_exists(self._model.__table_name__)
|
72
84
|
|
73
85
|
@override
|
86
|
+
@clear_list
|
74
87
|
def insert(self, instances: T | list[T]) -> None:
|
75
88
|
insert = InsertQuery(self._model, self._repository)
|
76
89
|
insert.insert(instances)
|
77
90
|
insert.execute()
|
78
|
-
self._query_list.clear()
|
79
91
|
return None
|
80
92
|
|
81
93
|
@override
|
@@ -95,36 +107,33 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
|
|
95
107
|
return None
|
96
108
|
|
97
109
|
@override
|
110
|
+
@clear_list
|
98
111
|
def upsert(self, instances: T | list[T]) -> None:
|
99
112
|
upsert = UpsertQuery(self._model, self._repository)
|
100
113
|
upsert.upsert(instances)
|
101
114
|
upsert.execute()
|
102
|
-
self._query_list.clear()
|
103
115
|
return None
|
104
116
|
|
105
117
|
@override
|
118
|
+
@clear_list
|
106
119
|
def update(self, dicc: dict[str, Any] | list[dict[str, Any]]) -> None:
|
107
120
|
update = UpdateQuery(self._model, self._repository, self._query_list["where"])
|
108
121
|
update.update(dicc)
|
109
122
|
update.execute()
|
110
|
-
|
123
|
+
|
111
124
|
return None
|
112
125
|
|
113
126
|
@override
|
114
127
|
def limit(self, number: int) -> IStatements_two_generic[T, MySQLConnection]:
|
115
128
|
limit = LimitQuery(number)
|
116
129
|
# Only can be one LIMIT SQL parameter. We only use the last LimitQuery
|
117
|
-
|
118
|
-
if len(limit_list) > 0:
|
119
|
-
self._query_list["limit"] = [limit]
|
120
|
-
else:
|
121
|
-
self._query_list["limit"].append(limit)
|
130
|
+
self._query_list["limit"] = [limit]
|
122
131
|
return self
|
123
132
|
|
124
133
|
@override
|
125
134
|
def offset(self, number: int) -> IStatements_two_generic[T, MySQLConnection]:
|
126
135
|
offset = OffsetQuery(number)
|
127
|
-
self._query_list["offset"]
|
136
|
+
self._query_list["offset"] = [offset]
|
128
137
|
return self
|
129
138
|
|
130
139
|
@override
|
@@ -157,7 +166,7 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
|
|
157
166
|
return self
|
158
167
|
|
159
168
|
@override
|
160
|
-
def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type:
|
169
|
+
def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderTypes) -> IStatements_two_generic[T, MySQLConnection]:
|
161
170
|
order = OrderQuery[T](self._model, _lambda_col, order_type)
|
162
171
|
self._query_list["order"].append(order)
|
163
172
|
return self
|
@@ -193,7 +202,7 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
|
|
193
202
|
|
194
203
|
query: str = self._build()
|
195
204
|
if flavour:
|
196
|
-
result = self._return_flavour(query, flavour)
|
205
|
+
result = self._return_flavour(query, flavour, select)
|
197
206
|
if issubclass(flavour, tuple) and isinstance(selector(self._model), property):
|
198
207
|
return tuple([x[0] for x in result])
|
199
208
|
return result
|
@@ -227,9 +236,9 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
|
|
227
236
|
return self
|
228
237
|
|
229
238
|
@override
|
239
|
+
@clear_list
|
230
240
|
def _build(self) -> str:
|
231
|
-
|
232
|
-
|
241
|
+
query_list: list[str] = []
|
233
242
|
for x in self.__order__:
|
234
243
|
sub_query: Optional[list[IQuery]] = self._query_list.get(x, None)
|
235
244
|
if sub_query is None:
|
@@ -256,9 +265,8 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
|
|
256
265
|
else:
|
257
266
|
query_ = "\n".join([x.query for x in sub_query])
|
258
267
|
|
259
|
-
|
260
|
-
|
261
|
-
return query
|
268
|
+
query_list.append(query_)
|
269
|
+
return "\n".join(query_list)
|
262
270
|
|
263
271
|
def __build_where_clause(self, where_condition: list[AbstractWhere]) -> str:
|
264
272
|
query: str = where_condition[0].query
|
ormlambda/utils/column.py
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
-
from
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import Type, Optional, Callable, TYPE_CHECKING, Any
|
3
|
+
import shapely as sph
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from .table_constructor import Field
|
2
7
|
|
3
8
|
|
4
9
|
class Column[T]:
|
10
|
+
CHAR: str = "%s"
|
11
|
+
|
5
12
|
__slots__ = (
|
6
13
|
"dtype",
|
7
14
|
"column_name",
|
@@ -31,22 +38,54 @@ class Column[T]:
|
|
31
38
|
self.is_auto_increment: bool = is_auto_increment
|
32
39
|
self.is_unique: bool = is_unique
|
33
40
|
|
41
|
+
@property
|
42
|
+
def column_value_to_query(self) -> T:
|
43
|
+
"""
|
44
|
+
This property must ensure that any variable requiring casting by different database methods is properly wrapped.
|
45
|
+
"""
|
46
|
+
if self.dtype is sph.Point:
|
47
|
+
return sph.to_wkt(self.column_value, -1)
|
48
|
+
return self.column_value
|
49
|
+
|
50
|
+
@property
|
51
|
+
def placeholder(self) -> str:
|
52
|
+
return self.placeholder_resolutor(self.dtype)
|
53
|
+
|
54
|
+
@property
|
55
|
+
def placeholder_resolutor(self) -> Callable[[Type, T], str]:
|
56
|
+
return self.__fetch_wrapped_method
|
57
|
+
|
58
|
+
# FIXME [ ]: this method is allocating the Column class with MySQL database
|
59
|
+
@classmethod
|
60
|
+
def __fetch_wrapped_method(cls, type_: Type) -> Optional[str]:
|
61
|
+
"""
|
62
|
+
This method must ensure that any variable requiring casting by different database methods is properly wrapped.
|
63
|
+
"""
|
64
|
+
caster: dict[Type[Any], Callable[[str], str]] = {
|
65
|
+
sph.Point: lambda x: f"ST_GeomFromText({x})",
|
66
|
+
}
|
67
|
+
return caster.get(type_, lambda x: x)(cls.CHAR)
|
68
|
+
|
34
69
|
def __repr__(self) -> str:
|
35
|
-
return f"<Column: {self.
|
70
|
+
return f"<Column: {self.dtype}>"
|
36
71
|
|
37
|
-
def __to_string__(self,
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
"
|
72
|
+
def __to_string__(self, field: Field):
|
73
|
+
column_class_string: str = f"{Column.__name__}[{field.type_name}]("
|
74
|
+
|
75
|
+
dicc: dict[str, Callable[[Field], str]] = {
|
76
|
+
"dtype": lambda field: field.type_name,
|
77
|
+
"column_name": lambda field: f"'{field.name}'",
|
78
|
+
"column_value": lambda field: field.name, # must be the same variable name as the instance variable name in Table's __init__ class
|
42
79
|
}
|
43
|
-
|
44
|
-
|
45
|
-
|
80
|
+
for self_var in self.__init__.__annotations__:
|
81
|
+
if not hasattr(self, self_var):
|
82
|
+
continue
|
83
|
+
|
84
|
+
self_value = dicc.get(self_var, lambda field: getattr(self, self_var))(field)
|
85
|
+
column_class_string += f" {self_var}={self_value}, "
|
46
86
|
|
47
|
-
|
48
|
-
|
49
|
-
return exec_str
|
87
|
+
column_class_string += ")"
|
88
|
+
return column_class_string
|
50
89
|
|
51
90
|
def __hash__(self) -> int:
|
52
91
|
return hash(
|
ormlambda/utils/dtypes.py
CHANGED
@@ -48,8 +48,10 @@ MySQL 8.0 does not support year in two-digit format.
|
|
48
48
|
"""
|
49
49
|
|
50
50
|
from decimal import Decimal
|
51
|
-
import datetime
|
52
51
|
from typing import Any, Literal
|
52
|
+
import datetime
|
53
|
+
|
54
|
+
from shapely import Point
|
53
55
|
import numpy as np
|
54
56
|
|
55
57
|
from .column import Column
|
@@ -66,17 +68,7 @@ DATE = Literal["DATE", "DATETIME(fsp)", "TIMESTAMP(fsp)", "TIME(fsp)", "YEAR"]
|
|
66
68
|
def transform_py_dtype_into_query_dtype(dtype: Any) -> str:
|
67
69
|
# TODOL: must be found a better way to convert python data type into SQL clauses
|
68
70
|
# float -> DECIMAL(5,2) is an error
|
69
|
-
dicc: dict[Any, str] = {
|
70
|
-
int: "INTEGER",
|
71
|
-
float: "FLOAT(5,2)",
|
72
|
-
Decimal: "FLOAT",
|
73
|
-
datetime.datetime: "DATETIME",
|
74
|
-
datetime.date: "DATE",
|
75
|
-
bytes: "BLOB",
|
76
|
-
bytearray: "BLOB",
|
77
|
-
str: "VARCHAR(255)",
|
78
|
-
np.uint64: "BIGINT UNSIGNED",
|
79
|
-
}
|
71
|
+
dicc: dict[Any, str] = {int: "INTEGER", float: "FLOAT(5,2)", Decimal: "FLOAT", datetime.datetime: "DATETIME", datetime.date: "DATE", bytes: "BLOB", bytearray: "BLOB", str: "VARCHAR(255)", np.uint64: "BIGINT UNSIGNED", Point: "Point"}
|
80
72
|
|
81
73
|
res = dicc.get(dtype, None)
|
82
74
|
if res is None:
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import typing as tp
|
2
|
+
from .column import Column
|
3
|
+
|
4
|
+
__all__ = ["get_fields"]
|
5
|
+
|
6
|
+
MISSING = lambda: Column() # COMMENT: Very Important to avoid reusing the same variable across different classes. # noqa: E731
|
7
|
+
|
8
|
+
|
9
|
+
class Field[TProp: tp.AnnotatedAny]:
|
10
|
+
def __init__(self, name: str, type_: tp.Type, default: Column[TProp]) -> None:
|
11
|
+
self.name: str = name
|
12
|
+
self.type_: tp.Type[TProp] = type_
|
13
|
+
self.default: Column[TProp] = default
|
14
|
+
|
15
|
+
def __repr__(self) -> str:
|
16
|
+
return f"{Field.__name__}(name = {self.name}, type_ = {self.type_}, default = {self.default})"
|
17
|
+
|
18
|
+
@property
|
19
|
+
def has_default(self) -> bool:
|
20
|
+
return self.default is not MISSING()
|
21
|
+
|
22
|
+
@property
|
23
|
+
def init_arg(self) -> str:
|
24
|
+
default = f"={self.default_name}" # if self.has_default else ""}"
|
25
|
+
return f"{self.name}: {self.type_name}{default}"
|
26
|
+
|
27
|
+
@property
|
28
|
+
def default_name(self) -> str:
|
29
|
+
return f"_dflt_{self.name}"
|
30
|
+
|
31
|
+
@property
|
32
|
+
def type_name(self) -> str:
|
33
|
+
return f"_type_{self.name}"
|
34
|
+
|
35
|
+
@property
|
36
|
+
def assginment(self) -> str:
|
37
|
+
return f"self._{self.name} = {self.default.__to_string__(self)}"
|
38
|
+
|
39
|
+
|
40
|
+
def get_fields[T, TProp](cls: tp.Type[T]) -> tp.Iterable[Field]:
|
41
|
+
# COMMENT: Used the 'get_type_hints' method to resolve typing when 'from __future__ import annotations' is in use
|
42
|
+
annotations = {key: val for key, val in tp.get_type_hints(cls).items() if not key.startswith("_")}
|
43
|
+
|
44
|
+
# delete_special_variables(annotations)
|
45
|
+
fields = []
|
46
|
+
for name, type_ in annotations.items():
|
47
|
+
if hasattr(type_, "__origin__") and type_.__origin__ is Column: # __origin__ to get type of Generic value
|
48
|
+
field_type = type_.__args__[0]
|
49
|
+
else:
|
50
|
+
# type_ must by Column object
|
51
|
+
field_type: TProp = type_
|
52
|
+
|
53
|
+
default: Column = getattr(cls, name, MISSING())
|
54
|
+
|
55
|
+
default.dtype = field_type # COMMENT: Useful for setting the dtype variable after instantiation.
|
56
|
+
fields.append(Field[TProp](name, field_type, default))
|
57
|
+
|
58
|
+
# Update __annotations__ to create Columns
|
59
|
+
cls.__annotations__[name] = default
|
60
|
+
return fields
|
@@ -1,75 +1,21 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from decimal import Decimal
|
3
|
+
from typing import Any, Optional, Type, dataclass_transform, overload, TYPE_CHECKING
|
1
4
|
import base64
|
2
5
|
import datetime
|
3
|
-
from decimal import Decimal
|
4
|
-
from typing import Any, Iterable, Optional, Type, dataclass_transform, get_type_hints
|
5
6
|
import json
|
6
7
|
|
7
|
-
|
8
|
-
from .module_tree.dfs_traversal import DFSTraversal
|
9
|
-
from .column import Column
|
10
|
-
|
11
|
-
from .foreign_key import ForeignKey, TableInfo
|
12
|
-
|
13
|
-
MISSING = Column()
|
14
|
-
|
15
|
-
|
16
|
-
class Field:
|
17
|
-
def __init__(self, name: str, type_: Type, default: object) -> None:
|
18
|
-
self.name: str = name
|
19
|
-
self.type_: Type = type_
|
20
|
-
self.default: Column = default
|
21
|
-
|
22
|
-
def __repr__(self) -> str:
|
23
|
-
return f"{Field.__name__}(name = {self.name}, type_ = {self.type_}, default = {self.default})"
|
24
|
-
|
25
|
-
@property
|
26
|
-
def has_default(self) -> bool:
|
27
|
-
return self.default is not MISSING
|
8
|
+
import shapely as sph
|
28
9
|
|
29
|
-
@property
|
30
|
-
def init_arg(self) -> str:
|
31
|
-
# default = f"={self.default_name if self.has_default else None}"
|
32
|
-
default = f"={None}"
|
33
10
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@property
|
41
|
-
def type_name(self) -> str:
|
42
|
-
return f"_type_{self.name}"
|
43
|
-
|
44
|
-
@property
|
45
|
-
def assginment(self) -> str:
|
46
|
-
return f"self._{self.name} = {self.default.__to_string__(self.name,self.name,self.type_name)}"
|
47
|
-
|
48
|
-
|
49
|
-
def delete_special_variables(dicc: dict[str, object]) -> None:
|
50
|
-
keys = tuple(dicc.keys())
|
51
|
-
for key in keys:
|
52
|
-
if key.startswith("__"):
|
53
|
-
del dicc[key]
|
54
|
-
|
55
|
-
|
56
|
-
def get_fields[T](cls: Type[T]) -> Iterable[Field]:
|
57
|
-
# COMMENT: Used the 'get_type_hints' method to resolve typing when 'from __future__ import annotations' is in use
|
58
|
-
annotations = {key: val for key, val in get_type_hints(cls).items() if not key.startswith("_")}
|
59
|
-
|
60
|
-
# delete_special_variables(annotations)
|
61
|
-
fields = []
|
62
|
-
for name, type_ in annotations.items():
|
63
|
-
# type_ must by Column object
|
64
|
-
field_type = type_
|
65
|
-
if hasattr(type_, "__origin__") and type_.__origin__ is Column: # __origin__ to get type of Generic value
|
66
|
-
field_type = type_.__args__[0]
|
67
|
-
default: Column = getattr(cls, name, MISSING)
|
68
|
-
fields.append(Field(name, field_type, default))
|
11
|
+
from .column import Column
|
12
|
+
from .dtypes import get_query_clausule
|
13
|
+
from .fields import get_fields
|
14
|
+
from .foreign_key import ForeignKey, TableInfo
|
15
|
+
from .module_tree.dfs_traversal import DFSTraversal
|
69
16
|
|
70
|
-
|
71
|
-
|
72
|
-
return fields
|
17
|
+
if TYPE_CHECKING:
|
18
|
+
from .fields import Field
|
73
19
|
|
74
20
|
|
75
21
|
@dataclass_transform()
|
@@ -78,23 +24,32 @@ def __init_constructor__[T](cls: Type[T]) -> Type[T]:
|
|
78
24
|
# TODOL: I don't know if it's better to create a global dictionary like in commit '7de69443d7a8e7264b8d5d604c95da0e5d7e9cc0'
|
79
25
|
setattr(cls, "__properties_mapped__", {})
|
80
26
|
fields = get_fields(cls)
|
81
|
-
|
82
|
-
|
27
|
+
|
28
|
+
locals_: dict[str, Any] = {}
|
29
|
+
init_args: list[str] = ["self"]
|
30
|
+
assignments: list[str] = []
|
83
31
|
|
84
32
|
for field in fields:
|
85
|
-
if
|
86
|
-
|
33
|
+
if field.name.startswith("__"):
|
34
|
+
continue
|
35
|
+
|
36
|
+
locals_[field.type_name] = field.type_
|
37
|
+
locals_[field.default_name] = field.default.column_value
|
87
38
|
|
88
|
-
|
89
|
-
|
90
|
-
|
39
|
+
init_args.append(field.init_arg)
|
40
|
+
assignments.append(field.assginment)
|
41
|
+
__create_properties(cls, field)
|
42
|
+
|
43
|
+
string_locals_ = ", ".join(locals_)
|
44
|
+
string_init_args = ", ".join(init_args)
|
45
|
+
string_assignments = "\n\t\t".join(assignments)
|
91
46
|
|
92
47
|
wrapper_fn = "\n".join(
|
93
48
|
[
|
94
|
-
f"def wrapper({
|
95
|
-
f"
|
96
|
-
"\n
|
97
|
-
"
|
49
|
+
f"def wrapper({string_locals_}):",
|
50
|
+
f"\n\tdef __init__({string_init_args}):",
|
51
|
+
f"\n\t\t{string_assignments}",
|
52
|
+
"\treturn __init__",
|
98
53
|
]
|
99
54
|
)
|
100
55
|
|
@@ -109,11 +64,11 @@ def __init_constructor__[T](cls: Type[T]) -> Type[T]:
|
|
109
64
|
|
110
65
|
def __create_properties(cls: Type["Table"], field: Field) -> property:
|
111
66
|
_name: str = f"_{field.name}"
|
112
|
-
|
67
|
+
|
113
68
|
# we need to get Table attributes (Column class) and then called __getattribute__ or __setattr__ to make changes inside of Column
|
114
69
|
prop = property(
|
115
|
-
fget=lambda self:
|
116
|
-
fset=lambda self, value:
|
70
|
+
fget=lambda self: getattr(self, _name).__getattribute__("column_value"),
|
71
|
+
fset=lambda self, value: getattr(self, _name).__setattr__("column_value", value),
|
117
72
|
)
|
118
73
|
|
119
74
|
# set property in public name
|
@@ -122,22 +77,6 @@ def __create_properties(cls: Type["Table"], field: Field) -> property:
|
|
122
77
|
return None
|
123
78
|
|
124
79
|
|
125
|
-
def __transform_getter[T](obj: object, type_: T) -> T:
|
126
|
-
return obj.__getattribute__("column_value")
|
127
|
-
|
128
|
-
# if type_ is str and isinstance(eval(obj), Iterable):
|
129
|
-
# getter = eval(obj)
|
130
|
-
# return getter
|
131
|
-
|
132
|
-
|
133
|
-
def __transform_setter[T](obj: object, value: Any, type_: T) -> None:
|
134
|
-
return obj.__setattr__("column_value", value)
|
135
|
-
|
136
|
-
# if type_ is list:
|
137
|
-
# setter = str(setter)
|
138
|
-
# return None
|
139
|
-
|
140
|
-
|
141
80
|
class TableMeta(type):
|
142
81
|
def __new__[T](cls: "Table", name: str, bases: tuple, dct: dict[str, Any]) -> Type[T]:
|
143
82
|
"""
|
@@ -244,6 +183,7 @@ class Table(metaclass=TableMeta):
|
|
244
183
|
Decimal: str,
|
245
184
|
bytes: byte_to_string,
|
246
185
|
set: list,
|
186
|
+
sph.Point: lambda x: sph.to_wkt(x, rounding_precision=-1),
|
247
187
|
}
|
248
188
|
|
249
189
|
if (dtype := type(_value)) in transform_map:
|
@@ -324,3 +264,35 @@ class Table(metaclass=TableMeta):
|
|
324
264
|
)
|
325
265
|
)
|
326
266
|
return False
|
267
|
+
|
268
|
+
@classmethod
|
269
|
+
def get_property_name(cls, _property: property) -> str:
|
270
|
+
name: str = cls.__properties_mapped__.get(_property, None)
|
271
|
+
if not name:
|
272
|
+
raise KeyError(f"Class '{cls.__name__}' has not propery '{_property}' mapped.")
|
273
|
+
return name
|
274
|
+
|
275
|
+
@overload
|
276
|
+
@classmethod
|
277
|
+
def get_column(cls, column: str) -> Column: ...
|
278
|
+
@overload
|
279
|
+
@classmethod
|
280
|
+
def get_column(cls, column: property) -> Column: ...
|
281
|
+
@overload
|
282
|
+
@classmethod
|
283
|
+
def get_column[TProp](cls, column: property, value: TProp) -> Column[TProp]: ...
|
284
|
+
@overload
|
285
|
+
@classmethod
|
286
|
+
def get_column[TProp](cls, column: str, value: TProp) -> Column[TProp]: ...
|
287
|
+
@classmethod
|
288
|
+
def get_column[TProp](cls, column: str | property, value: Optional[TProp] = None) -> Column[TProp]:
|
289
|
+
if isinstance(column, property):
|
290
|
+
_column = cls.get_property_name(column)
|
291
|
+
elif isinstance(column, str) and column in cls.get_columns():
|
292
|
+
_column = column
|
293
|
+
else:
|
294
|
+
raise ValueError(f"'Column' param with value'{column}' is not expected.")
|
295
|
+
|
296
|
+
instance_table: Table = cls(**{_column: value})
|
297
|
+
|
298
|
+
return getattr(instance_table, f"_{_column}")
|
@@ -1,14 +1,15 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ormlambda
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.9.0
|
4
4
|
Summary: ORM designed to interact with the database (currently with MySQL) using lambda functions and nested functions
|
5
5
|
Author: p-hzamora
|
6
6
|
Author-email: p.hzamora@icloud.com
|
7
7
|
Requires-Python: >=3.12,<4.0
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
9
9
|
Classifier: Programming Language :: Python :: 3.12
|
10
|
-
Requires-Dist: fluent-validation (
|
10
|
+
Requires-Dist: fluent-validation (==4.3.1)
|
11
11
|
Requires-Dist: mysql-connector-python (>=9.0.0,<10.0.0)
|
12
|
+
Requires-Dist: shapely (>=2.0.6,<3.0.0)
|
12
13
|
Description-Content-Type: text/markdown
|
13
14
|
|
14
15
|

|
@@ -1,8 +1,8 @@
|
|
1
|
-
ormlambda/__init__.py,sha256=
|
1
|
+
ormlambda/__init__.py,sha256=lWQxjf2cQ2bXenNaDpoy2Bar6imiPlzc4nK0hkIYhC0,723
|
2
2
|
ormlambda/common/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
3
3
|
ormlambda/common/abstract_classes/__init__.py,sha256=tk2J4Mn_nD-1ZjtMVBE5FH7KR_8ppN_1Kx1s6c38GjM,167
|
4
|
-
ormlambda/common/abstract_classes/abstract_model.py,sha256=
|
5
|
-
ormlambda/common/abstract_classes/decomposition_query.py,sha256=
|
4
|
+
ormlambda/common/abstract_classes/abstract_model.py,sha256=W7E3DDeFeQbnBX0ccLqmhUX3dCHHDCADK3bT2wyPEtk,4618
|
5
|
+
ormlambda/common/abstract_classes/decomposition_query.py,sha256=0k1cTFftZZaRmjuYOEnZ-r7nqljTwcSlz1ZbEElnlbk,12586
|
6
6
|
ormlambda/common/abstract_classes/non_query_base.py,sha256=5jhvyT7OZaJxlGp9XMP3vQ4ei5QQZBn-fFtJnD640mE,980
|
7
7
|
ormlambda/common/abstract_classes/query_base.py,sha256=6qUFPwsVx45kUW3b66pHiSyjhcH4mzbdkddlGeUnG7c,266
|
8
8
|
ormlambda/common/enums/__init__.py,sha256=4lVKCHi1JalwgNzjsAXqX-C54NJEH83y2v5baMO8fN4,103
|
@@ -13,7 +13,7 @@ ormlambda/common/interfaces/IDecompositionQuery.py,sha256=dHdCxezbWwy-c4U4po2hQB
|
|
13
13
|
ormlambda/common/interfaces/INonQueryCommand.py,sha256=7CjLW4sKqkR5zUIGvhRXOtzTs6vypJW1a9EJHlgCw2c,260
|
14
14
|
ormlambda/common/interfaces/IQueryCommand.py,sha256=hfzCosK4-n8RJIb2PYs8b0qU3TNmfYluZXBf47KxxKs,331
|
15
15
|
ormlambda/common/interfaces/IRepositoryBase.py,sha256=zGm7tDrFLKj3FMYN-MWI-em3INws27g2yByNYYMx0qk,1126
|
16
|
-
ormlambda/common/interfaces/IStatements.py,sha256=
|
16
|
+
ormlambda/common/interfaces/IStatements.py,sha256=XJ0hCp7_7wMclPvZmavpdr7unQshOXKZDasgVk6RfwU,10409
|
17
17
|
ormlambda/common/interfaces/__init__.py,sha256=00ca9a-u_A8DzyEyxPfBMxfqLKFzzUgJaeNmoRitAbA,360
|
18
18
|
ormlambda/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
ormlambda/components/delete/IDelete.py,sha256=06ZEdbKBxsHSwsGMBu0E1om4WJjojZAm-L3b95eQrcc,139
|
@@ -39,13 +39,13 @@ ormlambda/databases/my_sql/clauses/delete.py,sha256=nUKNQgwF5YUfzk2icWpecYjrGk5D
|
|
39
39
|
ormlambda/databases/my_sql/clauses/drop_database.py,sha256=nMM0YUbcH0D9X3bU70Uc6S_dsIrAZy-IrYuIKrQZNrg,505
|
40
40
|
ormlambda/databases/my_sql/clauses/drop_table.py,sha256=meX4e-pVPQ7UwlPSHV5e9HHRblI1BlkLSc7ssl8WUiI,592
|
41
41
|
ormlambda/databases/my_sql/clauses/group_by.py,sha256=xG8YhdaDWBm99EFMkzCsBJNhHOJy5lvXmpaHu3jClro,1042
|
42
|
-
ormlambda/databases/my_sql/clauses/insert.py,sha256=
|
42
|
+
ormlambda/databases/my_sql/clauses/insert.py,sha256=mnOy62U4go0Ub6tmmgn8DRRWvPN12WRE5lqpCNbyR70,3136
|
43
43
|
ormlambda/databases/my_sql/clauses/joins.py,sha256=U6JnUvQo7AXyEeK-X1jMvckXefgAB7ugSmJCZhH1XQI,3058
|
44
44
|
ormlambda/databases/my_sql/clauses/limit.py,sha256=a4lI8FVRKpfXwBQTXdkbVtlQkmzcjE20ymiCy1IaSc4,391
|
45
45
|
ormlambda/databases/my_sql/clauses/offset.py,sha256=81170JhsQndjKlDfQj1ll-tiYHQbW8SuU4IE3mhQF7Y,395
|
46
|
-
ormlambda/databases/my_sql/clauses/order.py,sha256=
|
47
|
-
ormlambda/databases/my_sql/clauses/select.py,sha256=
|
48
|
-
ormlambda/databases/my_sql/clauses/update.py,sha256=
|
46
|
+
ormlambda/databases/my_sql/clauses/order.py,sha256=XTMtR5ObAJxq8eTHp392rykQD991ecJ95dyXXLUpgeU,1680
|
47
|
+
ormlambda/databases/my_sql/clauses/select.py,sha256=o0gjCt8cZfTkMsJwZcCt0XkSeFa2rlKz-0Ymi7XL5xU,1833
|
48
|
+
ormlambda/databases/my_sql/clauses/update.py,sha256=d2nSLiGe8OUk0ASgGxchit_1DL-Yg8U-DUtBbgpfkto,1571
|
49
49
|
ormlambda/databases/my_sql/clauses/upsert.py,sha256=eW2pQ4ax-GKuXiaWKoSRSS1GrHuILJBsmj83ADbBQ34,1951
|
50
50
|
ormlambda/databases/my_sql/clauses/where_condition.py,sha256=UgU5vnTqFAx91wKwnECpww5tETDZ9F7IdC_SiZOgZhI,8336
|
51
51
|
ormlambda/databases/my_sql/functions/__init__.py,sha256=hA8t3mUpV2p-pO4TVp5rjC5Yp7aIkWPsS8NpLi3DUh0,171
|
@@ -53,12 +53,13 @@ ormlambda/databases/my_sql/functions/concat.py,sha256=cZztl5eSATpYMKVKfyPbul6Ooc
|
|
53
53
|
ormlambda/databases/my_sql/functions/max.py,sha256=zrO_RBKsHhyokEmSpPI6Yg5OY6Jf4GGp2RveBJdOuuA,1190
|
54
54
|
ormlambda/databases/my_sql/functions/min.py,sha256=SEVuUdIJNz9zM5za1kLTWalFkhErjsjyBb8SU8n0F94,1190
|
55
55
|
ormlambda/databases/my_sql/functions/sum.py,sha256=akKYr2dI8TZS5MDvybfHn_idhPOvEH0cj6mDRQIHe-M,1188
|
56
|
-
ormlambda/databases/my_sql/repository.py,sha256=
|
57
|
-
ormlambda/databases/my_sql/statements.py,sha256=
|
56
|
+
ormlambda/databases/my_sql/repository.py,sha256=fj_RcMY6QhANvKRyfAnu6PEfvkrpiBXrlTvmeXUf5Vo,8823
|
57
|
+
ormlambda/databases/my_sql/statements.py,sha256=ukP8ypxegCnxOuIEH99pNgWVUyOP-ELHD6GzfLEWUx4,12045
|
58
58
|
ormlambda/model_base.py,sha256=RrAATQWX_bHJ0ZQ5sCHyJKA4NiR7ZJY4I6dqhnGWWAc,1216
|
59
59
|
ormlambda/utils/__init__.py,sha256=ywMdWqmA2jHj19-W-S04yfaYF5hv4IZ1lZDq0B8Jnjs,142
|
60
|
-
ormlambda/utils/column.py,sha256=
|
61
|
-
ormlambda/utils/dtypes.py,sha256=
|
60
|
+
ormlambda/utils/column.py,sha256=SqbX8N63_RwXNrMXuVMOpatDw--aLc47o3kG1sEXhNs,3413
|
61
|
+
ormlambda/utils/dtypes.py,sha256=Ji4QOyKD0n9bKe7yXIIduy9uEX5BaXolQSIsx0NXYJY,7843
|
62
|
+
ormlambda/utils/fields.py,sha256=jyUJXJKblhLGqFGgAXkWJeE0FYLd5Ywd7H2pjQsfz8c,2128
|
62
63
|
ormlambda/utils/foreign_key.py,sha256=ewGLPtf1MrFogvwGm_jsSnOLAH2G9virXvLcc3co36I,2973
|
63
64
|
ormlambda/utils/lambda_disassembler/__init__.py,sha256=q23_F2Vp1_XgVpQSbWQPM5wxzRCZOr7ZMb9X5VG_YxU,229
|
64
65
|
ormlambda/utils/lambda_disassembler/dis_types.py,sha256=Myuo9-KSBIJSyr9jfLSDDe1jbrzyOqZNLufv6ODHm98,4824
|
@@ -70,8 +71,8 @@ ormlambda/utils/lambda_disassembler/tree_instruction.py,sha256=QUnhG89WKJyAlEWAj
|
|
70
71
|
ormlambda/utils/module_tree/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
71
72
|
ormlambda/utils/module_tree/dfs_traversal.py,sha256=lSF03G63XtJFLp03ueAmsHMBvhUkjptDbK3IugXm8iU,1425
|
72
73
|
ormlambda/utils/module_tree/dynamic_module.py,sha256=zwvjU3U2cz6H2CDp9Gncs5D5bSAyfITNa2SDqFDl8rw,8551
|
73
|
-
ormlambda/utils/table_constructor.py,sha256=
|
74
|
-
ormlambda-2.
|
75
|
-
ormlambda-2.
|
76
|
-
ormlambda-2.
|
77
|
-
ormlambda-2.
|
74
|
+
ormlambda/utils/table_constructor.py,sha256=ch1geCSJIQnnv_D_uzfYk6do533kjtZyeCIh2t0_dkU,10863
|
75
|
+
ormlambda-2.9.0.dist-info/LICENSE,sha256=xBprFw8GJLdHMOoUqDk0427EvjIcbEREvXXVFULuuXU,1080
|
76
|
+
ormlambda-2.9.0.dist-info/METADATA,sha256=t2WNOq0P72brj6Qr1h_PXY0oXRJ85NjY6oYbn7l2REs,8461
|
77
|
+
ormlambda-2.9.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
78
|
+
ormlambda-2.9.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|