ormlambda 2.8.0__py3-none-any.whl → 2.9.4__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,7 +1,8 @@
1
1
  from __future__ import annotations
2
- from typing import Any, Callable, Iterable, Optional, Literal, Type, Union, overload, TYPE_CHECKING, TypeVar
2
+ from typing import Any, Callable, Iterable, Optional, Literal, Type, Union, overload, TYPE_CHECKING
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,19 +11,54 @@ if TYPE_CHECKING:
10
11
  from ormlambda import Table
11
12
  from .IAggregate import IAggregate
12
13
 
13
- OrderType = Literal["ASC", "DESC"]
14
+
15
+ class OrderType(enum.Enum):
16
+ ASC = "ASC"
17
+ DESC = "DESC"
18
+
19
+
20
+ type OrderTypes = Literal["ASC", "DESC"] | OrderType | Iterable[OrderType]
21
+
22
+
23
+ type Tuple[T] = tuple[T, ...]
24
+
25
+ type SelectRes1[T1] = tuple[Tuple[T1]]
26
+ type SelectRes2[T1, T2] = tuple[*SelectRes1[T1], Tuple[T2]]
27
+ type SelectRes3[T1, T2, T3] = tuple[*SelectRes2[T1, T2], Tuple[T3]]
28
+ type SelectRes4[T1, T2, T3, T4] = tuple[*SelectRes3[T1, T2, T3], Tuple[T4]]
29
+ type SelectRes5[T1, T2, T3, T4, T5] = tuple[*SelectRes4[T1, T2, T3, T4], Tuple[T5]]
30
+ type SelectRes6[T1, T2, T3, T4, T5, T6] = tuple[*SelectRes5[T1, T2, T3, T4, T5], Tuple[T6]]
31
+ type SelectRes7[T1, T2, T3, T4, T5, T6, T7] = tuple[*SelectRes6[T1, T2, T3, T4, T5, T6], Tuple[T7]]
32
+ type SelectRes8[T1, T2, T3, T4, T5, T6, T7, T8] = tuple[*SelectRes7[T1, T2, T3, T4, T5, T6, T7], Tuple[T8]]
33
+ type SelectRes9[T1, T2, T3, T4, T5, T6, T7, T8, T9] = tuple[*SelectRes8[T1, T2, T3, T4, T5, T6, T7, T8], Tuple[T9]]
34
+ type SelectRes10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] = tuple[*SelectRes9[T1, T2, T3, T4, T5, T6, T7, T8, T9], Tuple[T10]]
35
+
36
+
37
+ type WhereCondition[T, T1] = Callable[[T, T1], bool]
38
+ type JoinCondition[T, T1] = tuple[T1, WhereCondition[T, T1]]
39
+
40
+ type TupleJoins1[T, T1] = tuple[JoinCondition[T, T1]]
41
+ type TupleJoins2[T, T1, T2] = tuple[*TupleJoins1[T, T1], JoinCondition[T, T2]]
42
+ type TupleJoins3[T, T1, T2, T3] = tuple[*TupleJoins2[T, T1, T2], JoinCondition[T, T3]]
43
+ type TupleJoins4[T, T1, T2, T3, T4] = tuple[*TupleJoins3[T, T1, T2, T3], JoinCondition[T, T4]]
44
+ type TupleJoins5[T, T1, T2, T3, T4, T5] = tuple[*TupleJoins4[T, T1, T2, T3, T4], JoinCondition[T, T5]]
45
+ type TupleJoins6[T, T1, T2, T3, T4, T5, T6] = tuple[*TupleJoins5[T, T1, T2, T3, T4, T5], JoinCondition[T, T6]]
46
+
14
47
 
15
48
  # TODOH: This var is duplicated from 'src\ormlambda\databases\my_sql\clauses\create_database.py'
16
49
  TypeExists = Literal["fail", "replace", "append"]
17
50
 
18
- T = TypeVar("T")
19
- WhereTypes = Union[Callable[[T], bool], Iterable[Callable[[T], bool]]]
51
+ type WhereTypes[T, *Ts] = Union[Callable[[T, *Ts], bool], Iterable[Callable[[T, *Ts], bool]]]
20
52
 
21
53
 
22
- class IStatements[T: Table](ABC):
54
+ class IStatements[T, *Ts](ABC):
23
55
  @abstractmethod
24
56
  def create_table(self, if_exists: TypeExists) -> None: ...
25
57
 
58
+ # #TODOL [ ]: We must to implement this mehtod
59
+ # @abstractmethod
60
+ # def drop_table(self)->None: ...
61
+
26
62
  @abstractmethod
27
63
  def table_exists(self) -> bool: ...
28
64
 
@@ -109,18 +145,13 @@ class IStatements[T: Table](ABC):
109
145
  @overload
110
146
  def delete(self, instance: list[T]) -> None: ...
111
147
  @abstractmethod
112
- def delete(self, instance: Optional[T | list[T]] = None) -> None: ...
148
+ def delete(self, instance: Optional[T | list[T]] = ...) -> None: ...
113
149
 
114
150
  # endregion
115
- # region join
116
- @abstractmethod
117
- def join(self, table_left: Table, table_right: Table, *, by: str) -> IStatements[T]: ...
118
151
 
119
- # endregion
120
152
  # region where
121
-
122
153
  @overload
123
- def where(self, conditions: Iterable[Callable[[T], bool]]) -> IStatements[T]:
154
+ def where(self, conditions: Iterable[Callable[[T, *Ts], bool]]) -> IStatements[T, *Ts]:
124
155
  """
125
156
  This method creates where clause by passing the Iterable in lambda function
126
157
  EXAMPLE
@@ -131,7 +162,7 @@ class IStatements[T: Table](ABC):
131
162
  ...
132
163
 
133
164
  @overload
134
- def where(self, conditions: Callable[[T], bool], **kwargs) -> IStatements[T]:
165
+ def where(self, conditions: Callable[[T, *Ts], bool], **kwargs) -> IStatements[T, *Ts]:
135
166
  """
136
167
  PARAM
137
168
  -
@@ -148,16 +179,16 @@ class IStatements[T: Table](ABC):
148
179
  ...
149
180
 
150
181
  @abstractmethod
151
- def where(self, conditions: WhereTypes = lambda: None, **kwargs) -> IStatements[T]: ...
182
+ def where(self, conditions: WhereTypes[T, *Ts] = lambda: None, **kwargs) -> IStatements[T, *Ts]: ...
152
183
 
153
184
  # endregion
154
185
  # region order
155
186
  @overload
156
187
  def order[TValue](self, _lambda_col: Callable[[T], TValue]) -> IStatements[T]: ...
157
188
  @overload
158
- def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderType) -> IStatements[T]: ...
189
+ def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderTypes) -> IStatements[T]: ...
159
190
  @abstractmethod
160
- def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderType) -> IStatements[T]: ...
191
+ def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderTypes) -> IStatements[T]: ...
161
192
 
162
193
  # endregion
163
194
  # region concat
@@ -191,72 +222,94 @@ class IStatements[T: Table](ABC):
191
222
  alias: bool = ...,
192
223
  alias_name: Optional[str] = ...,
193
224
  ) -> TProp: ...
225
+
226
+ # endregion
227
+ # region join
228
+
229
+ @overload
230
+ def join[T1](self, joins: JoinCondition[T, T1]) -> IStatements[T, T1]: ...
231
+ @overload
232
+ def join[T1](self, joins: TupleJoins1[T, T1]) -> IStatements[T, T1]: ...
233
+ @overload
234
+ def join[T1, T2](self, joins: TupleJoins2[T, T1, T2]) -> IStatements[T, T1, T2]: ...
235
+ @overload
236
+ def join[T1, T2, T3](self, joins: TupleJoins3[T, T1, T2, T3]) -> IStatements[T, T1, T2, T3]: ...
237
+ @overload
238
+ def join[T1, T2, T3, T4](self, joins: TupleJoins4[T, T1, T2, T3, T4]) -> IStatements[T, T1, T2, T3, T4]: ...
239
+ @overload
240
+ def join[T1, T2, T3, T4, T5](self, joins: TupleJoins5[T, T1, T2, T3, T4, T5]) -> IStatements[T, T1, T2, T3, T4, T5]: ...
241
+ @overload
242
+ def join[T1, T2, T3, T4, T5, T6](self, joins: TupleJoins6[T, T1, T2, T3, T4, T5, T6]) -> IStatements[T, T1, T2, T3, T4, T5, T6]: ...
243
+
244
+ @abstractmethod
245
+ def join[*FKTables](self, joins) -> IStatements[T, *FKTables]: ...
246
+
194
247
  # endregion
195
248
  # region select
196
249
  @overload
197
- def select(self) -> tuple[T, ...]: ...
250
+ def select(self) -> SelectRes1[T]: ...
198
251
  @overload
199
- def select[T1](self, selector: Callable[[T], T1], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...]]: ...
252
+ def select[T1](self, selector: Callable[[T], T1], *, by: Optional[Enum] = ...) -> SelectRes1[T1]: ...
200
253
  @overload
201
- def select[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...]]: ...
254
+ def select[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = ...) -> SelectRes1[T1]: ...
202
255
  @overload
203
- def select[T1, T2](self, selector: Callable[[T], tuple[T1, T2]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...]]: ...
256
+ def select[T1, T2](self, selector: Callable[[T, *Ts], tuple[T1, T2]], *, by: Optional[Enum] = ...) -> SelectRes2[T1, T2]: ...
204
257
  @overload
205
- def select[T1, T2, T3](self, selector: Callable[[T], tuple[T1, T2, T3]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...]]: ...
258
+ def select[T1, T2, T3](self, selector: Callable[[T, *Ts], tuple[T1, T2, T3]], *, by: Optional[Enum] = ...) -> SelectRes3[T1, T2, T3]: ...
206
259
  @overload
207
- def select[T1, T2, T3, T4](self, selector: Callable[[T], tuple[T1, T2, T3, T4]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...]]: ...
260
+ def select[T1, T2, T3, T4](self, selector: Callable[[T, *Ts], tuple[T1, T2, T3, T4]], *, by: Optional[Enum] = ...) -> SelectRes4[T1, T2, T3, T4]: ...
208
261
  @overload
209
- def select[T1, T2, T3, T4, T5](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...]]: ...
262
+ def select[T1, T2, T3, T4, T5](self, selector: Callable[[T, *Ts], tuple[T1, T2, T3, T4, T5]], *, by: Optional[Enum] = ...) -> SelectRes5[T1, T2, T3, T4, T5]: ...
210
263
  @overload
211
- def select[T1, T2, T3, T4, T5, T6](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...]]: ...
264
+ def select[T1, T2, T3, T4, T5, T6](self, selector: Callable[[T, *Ts], tuple[T1, T2, T3, T4, T5, T6]], *, by: Optional[Enum] = ...) -> SelectRes6[T1, T2, T3, T4, T5, T6]: ...
212
265
  @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] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...]]: ...
266
+ def select[T1, T2, T3, T4, T5, T6, T7](self, selector: Callable[[T, *Ts], tuple[T1, T2, T3, T4, T5, T6, T7]], *, by: Optional[Enum] = ...) -> SelectRes7[T1, T2, T3, T4, T5, T6, T7]: ...
214
267
  @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] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...]]: ...
268
+ def select[T1, T2, T3, T4, T5, T6, T7, T8](self, selector: Callable[[T, *Ts], tuple[T1, T2, T3, T4, T5, T6, T7, T8]], *, by: Optional[Enum] = ...) -> SelectRes8[T1, T2, T3, T4, T5, T6, T7, T8]: ...
216
269
  @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, ...]]: ...
270
+ def select[T1, T2, T3, T4, T5, T6, T7, T8, T9](self, selector: Callable[[T, *Ts], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9]], *, by: Optional[Enum] = ...) -> SelectRes9[T1, T2, T3, T4, T5, T6, T7, T8, T9]: ...
220
271
  @overload
221
- 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] = JoinType.INNER_JOIN
223
- ) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...], tuple[T9, ...], tuple[T10, ...]]: ...
272
+ def select[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](self, selector: Callable[[T, *Ts], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]], *, by: Optional[Enum] = ...) -> SelectRes10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]: ...
273
+
274
+ @overload
275
+ def select[TFlavour](self, selector: Optional[Callable[[T, *Ts], tuple]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour], by: Optional[Enum] = ..., **kwargs) -> TFlavour: ...
224
276
  @overload
225
- def select[Ts](self, selector: Optional[Callable[[T], Ts]] = None, *, flavour: Type[tuple], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[Ts, ...]: ...
277
+ def select[TRes](self, selector: Optional[Callable[[T, *Ts], TRes]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., **kwargs) -> tuple[TRes, ...]: ...
226
278
  @overload
227
- def select[Ts](self, selector: Optional[Callable[[T], tuple[Ts]]] = None, *, flavour: Type[tuple], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[Ts, ...]: ...
279
+ def select[TRes](self, selector: Optional[Callable[[T, *Ts], tuple[TRes]]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., **kwargs) -> tuple[TRes, ...]: ...
228
280
  @overload
229
- def select[*Ts](self, selector: Optional[Callable[[T], tuple[*Ts]]] = None, *, flavour: Type[tuple], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[*Ts]]: ...
281
+ def select[*TRes](self, selector: Optional[Callable[[T, *Ts], tuple[*TRes]]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., **kwargs) -> tuple[tuple[*TRes]]: ...
230
282
  @overload
231
- def select[TFlavour](self, selector: Optional[Callable[[T], tuple]] = None, *, flavour: Type[TFlavour], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[TFlavour]: ...
283
+ def select[TFlavour](self, selector: Optional[Callable[[T, *Ts], tuple]] = ..., *, flavour: Type[TFlavour], by: Optional[Enum] = ..., **kwargs) -> tuple[TFlavour]: ...
284
+
232
285
  @abstractmethod
233
- def select[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = lambda: None, *, flavour: Type[TFlavour] = None, by: JoinType = JoinType.INNER_JOIN): ...
286
+ def select[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T, *Ts], tuple[TValue, *Ts]]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour] = ..., by: JoinType = ..., **kwargs): ...
234
287
 
235
288
  # endregion
236
289
  # region select_one
237
290
  @overload
238
291
  def select_one(self) -> T: ...
239
292
  @overload
240
- def select_one[TFlavour](self, *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[TFlavour]) -> TFlavour: ...
293
+ def select_one[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour]) -> TFlavour: ...
241
294
  @overload
242
- def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> T1: ...
295
+ def select_one[T1](self, selector: Callable[[T, *Ts], tuple[T1]], *, by: Optional[Enum] = ...) -> T1: ...
243
296
  @overload
244
- def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[*Ts]: ...
297
+ def select_one[*TRes](self, selector: Callable[[T, *Ts], tuple[*TRes]], *, by: Optional[Enum] = ...) -> tuple[*TRes]: ...
245
298
  @overload
246
- def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type) -> T1: ...
299
+ def select_one[T1](self, selector: Callable[[T, *Ts], tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type) -> T1: ...
247
300
  @overload
248
- def select_one[T1, TFlavour](self, selector: Callable[[T], T1], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[TFlavour]) -> T1: ...
301
+ def select_one[T1, TFlavour](self, selector: Callable[[T, *Ts], T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour]) -> T1: ...
249
302
  @overload
250
- def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[tuple]) -> tuple[*Ts]: ...
303
+ def select_one[*Ts](self, selector: Callable[[T, *Ts], tuple[*Ts]], *, by: Optional[Enum] = ..., flavour: Type[tuple]) -> tuple[*Ts]: ...
251
304
  @overload
252
- def select_one[TFlavour](self, selector: Callable[[T], tuple], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[TFlavour]) -> TFlavour: ...
305
+ def select_one[TFlavour](self, selector: Callable[[T, *Ts], tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour]) -> TFlavour: ...
253
306
  @abstractmethod
254
- def select_one[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = lambda: None, *, flavour: Type[TFlavour] = None, by: Optional[Enum] = JoinType.INNER_JOIN): ...
307
+ def select_one[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T, *Ts], tuple[TValue, *Ts]]] = lambda: None, *, flavour: Type[TFlavour] = ..., by: Optional[Enum] = ...): ...
255
308
 
256
309
  # endregion
257
310
  # region group_by
258
311
  @abstractmethod
259
- def group_by[TRepo, *Ts](self, column: Callable[[T], TRepo]) -> IStatements[T]: ...
312
+ def group_by[TRepo](self, column: Callable[[T, *Ts], TRepo]) -> IStatements[T, *Ts]: ...
260
313
 
261
314
  # endregion
262
315
 
@@ -264,7 +317,16 @@ class IStatements[T: Table](ABC):
264
317
  def _build(self) -> str: ...
265
318
 
266
319
 
267
- class IStatements_two_generic[T: Table, TRepo](IStatements[T]):
320
+ class IStatements_two_generic[T: Table, *Ts, TRepo](IStatements[T, *Ts]):
268
321
  @property
269
322
  @abstractmethod
270
323
  def repository(self) -> IRepositoryBase[TRepo]: ...
324
+
325
+ @property
326
+ def query(self) -> str: ...
327
+
328
+ @property
329
+ def model(self) -> Type[T]: ...
330
+
331
+ @property
332
+ def models(self) -> tuple[*Ts]: ...
@@ -0,0 +1,31 @@
1
+ import typing as tp
2
+ from ormlambda.common.abstract_classes.decomposition_query import ClauseInfo, DecompositionQueryBase
3
+ from ormlambda import Table
4
+
5
+ from ormlambda.common.interfaces import ICustomAlias
6
+
7
+
8
+ class Alias[T: tp.Type[Table], *Ts](DecompositionQueryBase[T,*Ts], ICustomAlias[T,*Ts]):
9
+ def __init__(
10
+ self,
11
+ table: T,
12
+ query: tp.Callable[[T, *Ts], tp.Any],
13
+ *,
14
+ alias: bool = True,
15
+ alias_name: str | None = None,
16
+ ) -> None:
17
+ super().__init__(
18
+ table,
19
+ lambda_query=query,
20
+ alias=alias,
21
+ alias_name=alias_name,
22
+ )
23
+
24
+ def alias_children_resolver[Tclause: tp.Type[Table]](self, clause_info: ClauseInfo[Tclause]):
25
+ return self.alias_name
26
+
27
+ @property
28
+ def query(self) -> str:
29
+ assert len(self.all_clauses) == 1
30
+
31
+ return self.all_clauses[0].query
@@ -5,13 +5,13 @@ from ormlambda.common.interfaces.IAggregate import IAggregate
5
5
  from ormlambda import Table
6
6
 
7
7
 
8
- class GroupBy[T: tp.Type[Table], TProp](DecompositionQueryBase[T], IAggregate[T]):
8
+ class GroupBy[T: tp.Type[Table], *Ts, TProp](DecompositionQueryBase[T], IAggregate[T]):
9
9
  CLAUSE: str = "GROUP BY"
10
10
 
11
11
  def __init__(
12
12
  self,
13
13
  table: T,
14
- column: tp.Callable[[T], TProp],
14
+ column: tp.Callable[[T, *Ts], TProp],
15
15
  *,
16
16
  alias: bool = True,
17
17
  alias_name: str | None = None,
@@ -1,4 +1,4 @@
1
- from typing import Any, override, Iterable
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
- new_dict_list: list[dict[str, Any]] = []
28
- self.__fill_dict_list(new_dict_list, instances)
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
- self._values = [tuple(x.values()) for x in new_dict_list]
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[dict], values: T | list[T]):
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
- dicc: dict = {}
71
+ new_list = []
61
72
  for col in values.__dict__.values():
62
73
  if isinstance(col, Column) and self.__is_valid(col):
63
- dicc.update({col.column_name: col.column_value})
64
- list_dict.append(dicc)
65
- return list_dict
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,7 +1,9 @@
1
1
  from __future__ import annotations
2
- from typing import override, Callable, overload, Optional, TYPE_CHECKING
2
+ from collections import defaultdict
3
+ from typing import override, Callable, overload, Optional, TYPE_CHECKING, Type
3
4
 
4
5
 
6
+ from ormlambda.utils.module_tree.dfs_traversal import DFSTraversal
5
7
  from ormlambda.common.interfaces.IQueryCommand import IQuery
6
8
  from ormlambda import Disassembler
7
9
  from ormlambda import JoinType
@@ -21,6 +23,13 @@ class JoinSelector[TLeft, TRight](IQuery):
21
23
  "_compareop",
22
24
  )
23
25
 
26
+ @override
27
+ def __repr__(self) -> str:
28
+ table_col_left: str = f"{self._orig_table.__table_name__}.{self._left_col}"
29
+ table_col_right: str = f"{self._table_right.__table_name__}.{self._right_col}"
30
+
31
+ return f"{IQuery.__name__}: {self.__class__.__name__} ({table_col_left} == {table_col_right})"
32
+
24
33
  @overload
25
34
  def __init__(
26
35
  self,
@@ -102,3 +111,32 @@ class JoinSelector[TLeft, TRight](IQuery):
102
111
  right_col, # second_col
103
112
  ]
104
113
  return " ".join(list_)
114
+
115
+ @classmethod
116
+ def sort_join_selectors(cls, joins: set[JoinSelector]) -> tuple[JoinSelector]:
117
+ # FIXME [x]: How to sort when needed because it's not necessary at this point. It is for testing purpouse
118
+ if len(joins) == 1:
119
+ return tuple(joins)
120
+
121
+ join_object_map: dict[str, list[JoinSelector]] = defaultdict(list)
122
+
123
+ for obj in joins:
124
+ join_object_map[obj._orig_table].append(obj)
125
+
126
+ graph: dict[Type[Table], list[Type[Table]]] = defaultdict(list)
127
+ for join in joins:
128
+ graph[join._orig_table].append(join._table_right)
129
+
130
+ sorted_graph = DFSTraversal.sort(graph)[::-1]
131
+
132
+ if not sorted_graph:
133
+ return tuple(joins)
134
+
135
+ res = []
136
+ for table in sorted_graph:
137
+ tables = join_object_map[table]
138
+
139
+ if not tables:
140
+ continue
141
+ res.extend(tables)
142
+ return res
@@ -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.utils.lambda_disassembler.tree_instruction import TreeInstruction
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, order_lambda: Callable[[T], None], order_type: OrderType) -> None:
19
- if not self._valid_order_type(order_type):
20
- raise Exception("order_type only can be 'ASC' or 'DESC'")
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._instance: T = instance
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 _valid_order_type(self, _value: str) -> bool:
28
- return _value in (ASC, DESC)
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
- return f"{self.ORDER} {self._instance.__table_name__}.{self._column} {self._order_type}"
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)}"
@@ -1,53 +1,60 @@
1
- from typing import override, Type, Callable, TYPE_CHECKING
1
+ from __future__ import annotations
2
+ from typing import override, Type, Callable, TYPE_CHECKING, Optional
2
3
 
3
4
  from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase
4
5
  from ormlambda.common.enums.join_type import JoinType
5
6
  from ormlambda.common.interfaces.IAggregate import IAggregate
7
+ import shapely as shp
8
+
6
9
 
7
10
  if TYPE_CHECKING:
8
11
  from ormlambda import Table
12
+ from .joins import JoinSelector
9
13
 
10
14
 
11
- class Select[T: Type[Table]](DecompositionQueryBase[T]):
15
+ class Select[T: Type[Table], *Ts](DecompositionQueryBase[T, *Ts]):
12
16
  CLAUSE: str = "SELECT"
13
17
 
14
18
  def __init__(
15
19
  self,
16
- table: T,
20
+ tables: tuple[T, *Ts],
17
21
  lambda_query: Callable[[T], tuple] = lambda x: x,
18
22
  *,
19
23
  alias: bool = False,
20
24
  alias_name: str | None = None,
25
+ joins: Optional[list[JoinSelector]] = None,
21
26
  by: JoinType = JoinType.INNER_JOIN,
22
27
  ) -> None:
23
28
  super().__init__(
24
- table,
29
+ tables,
25
30
  lambda_query,
26
31
  alias=alias,
27
32
  alias_name=alias_name,
28
33
  by=by,
34
+ joins=joins,
29
35
  )
30
36
 
31
37
  # @classmethod
32
38
  # def alias_children_resolver[Tclause: Type[Table]](self, clause_info: ClauseInfo[Tclause]):
33
39
  # return f"{clause.table.__table_name__}_{name}"
34
40
 
41
+ # TODOL: see who to deal when we will have to add more mysql methods
35
42
  @override
36
43
  @property
37
44
  def query(self) -> str:
38
- cols:list[str] = []
45
+ cols: list[str] = []
39
46
  for x in self.all_clauses:
40
- cols.append(x.query)
41
-
42
- if isinstance(x._row_column,IAggregate) and x._row_column.has_foreign_keys:
43
- self._fk_relationship.update(x._row_column.fk_relationship)
47
+ if x.dtype is shp.Point:
48
+ cols.append(x.concat_with_alias(f"ST_AsText({self.table.__table_name__}.{x.column})"))
49
+ else:
50
+ cols.append(x.query)
44
51
 
52
+ if isinstance(x._row_column, IAggregate) and x._row_column.has_foreign_keys:
53
+ self._joins.update(x._row_column.fk_relationship)
45
54
 
46
55
  col: str = ", ".join(cols)
47
- query: str = f"{self.CLAUSE} {col} FROM {self._table.__table_name__}"
48
- alias = ""
56
+ query: str = f"{self.CLAUSE} {col} FROM {self.table.__table_name__}"
49
57
 
50
- query += alias
51
58
  if self.has_foreign_keys:
52
59
  query += " " + self.stringify_foreign_key(" ")
53
60
 
@@ -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[str] = []
30
+ name_cols: list[Column] = []
31
31
 
32
32
  for col, value in dicc.items():
33
- if isinstance(col, str):
34
- string_col = col
35
- else:
36
- string_col = self._model.__properties_mapped__.get(col, None)
37
- if not string_col:
38
- raise KeyError(f"Class '{self._model.__name__}' has not {col} mapped.")
39
- if self.__is_valid__(string_col, value):
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: str, value: Any) -> bool:
49
- instance_table: Table = self._model(**{col: value})
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