ormlambda 3.7.2__py3-none-any.whl → 3.11.1__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 +2 -0
- ormlambda/databases/my_sql/caster/caster.py +1 -0
- ormlambda/databases/my_sql/clauses/__init__.py +1 -0
- ormlambda/databases/my_sql/clauses/alias.py +15 -21
- ormlambda/databases/my_sql/clauses/group_by.py +19 -20
- ormlambda/databases/my_sql/clauses/having.py +16 -0
- ormlambda/databases/my_sql/clauses/order.py +6 -1
- ormlambda/databases/my_sql/clauses/where.py +3 -3
- ormlambda/databases/my_sql/functions/concat.py +8 -6
- ormlambda/databases/my_sql/functions/max.py +1 -1
- ormlambda/databases/my_sql/join_context.py +3 -2
- ormlambda/databases/my_sql/repository/repository.py +57 -11
- ormlambda/databases/my_sql/statements.py +83 -31
- ormlambda/engine/__init__.py +2 -0
- ormlambda/engine/create.py +35 -0
- ormlambda/engine/url.py +744 -0
- ormlambda/engine/utils.py +17 -0
- ormlambda/repository/base_repository.py +0 -1
- ormlambda/sql/column.py +27 -2
- ormlambda/sql/foreign_key.py +36 -4
- ormlambda/statements/interfaces/IStatements.py +49 -42
- ormlambda/statements/types.py +9 -3
- {ormlambda-3.7.2.dist-info → ormlambda-3.11.1.dist-info}/METADATA +107 -8
- {ormlambda-3.7.2.dist-info → ormlambda-3.11.1.dist-info}/RECORD +26 -22
- {ormlambda-3.7.2.dist-info → ormlambda-3.11.1.dist-info}/LICENSE +0 -0
- {ormlambda-3.7.2.dist-info → ormlambda-3.11.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
from typing import Optional, Any, TypeGuard, Iterable
|
2
|
+
import collections.abc as collections_abc
|
3
|
+
|
4
|
+
|
5
|
+
def is_non_string_iterable(obj: Any) -> TypeGuard[Iterable[Any]]:
|
6
|
+
return isinstance(obj, collections_abc.Iterable) and not isinstance(obj, (str, bytes))
|
7
|
+
|
8
|
+
|
9
|
+
def to_list(x: Any, default: Optional[list[Any]] = None) -> list[Any]:
|
10
|
+
if x is None:
|
11
|
+
return default # type: ignore
|
12
|
+
if not is_non_string_iterable(x):
|
13
|
+
return [x]
|
14
|
+
elif isinstance(x, list):
|
15
|
+
return x
|
16
|
+
else:
|
17
|
+
return list(x)
|
ormlambda/sql/column.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from typing import Iterable, Type, Optional, TYPE_CHECKING
|
2
|
+
from typing import Iterable, Type, Optional, TYPE_CHECKING, overload
|
3
3
|
import abc
|
4
4
|
from ormlambda.sql.types import TableType, ComparerType, ColumnType
|
5
5
|
from ormlambda import ConditionType
|
@@ -25,18 +25,41 @@ class Column[TProp]:
|
|
25
25
|
"_check",
|
26
26
|
)
|
27
27
|
|
28
|
+
@overload
|
29
|
+
def __init__(self, *, column_name: str): ...
|
30
|
+
|
31
|
+
@overload
|
28
32
|
def __init__[T: Table](
|
29
33
|
self,
|
30
34
|
dtype: Type[TProp],
|
35
|
+
*,
|
31
36
|
is_primary_key: bool = False,
|
32
37
|
is_auto_generated: bool = False,
|
33
38
|
is_auto_increment: bool = False,
|
34
39
|
is_unique: bool = False,
|
35
40
|
check_types: bool = True,
|
41
|
+
) -> None: ...
|
42
|
+
|
43
|
+
def __init__[T: Table](
|
44
|
+
self,
|
45
|
+
dtype: Optional[Type[TProp]] = None,
|
46
|
+
*,
|
47
|
+
is_primary_key: bool = False,
|
48
|
+
is_auto_generated: bool = False,
|
49
|
+
is_auto_increment: bool = False,
|
50
|
+
is_unique: bool = False,
|
51
|
+
check_types: bool = True,
|
52
|
+
column_name: Optional[str] = None,
|
36
53
|
) -> None:
|
54
|
+
if dtype is None and column_name is None:
|
55
|
+
raise AttributeError("You must specify either the 'dtype' or 'column_name' attribute.")
|
56
|
+
|
57
|
+
if column_name is not None:
|
58
|
+
dtype = type(column_name)
|
59
|
+
|
37
60
|
self.dtype: Type[TProp] = dtype
|
38
61
|
self.table: Optional[TableType[T]] = None
|
39
|
-
self.column_name: Optional[str] =
|
62
|
+
self.column_name: Optional[str] = column_name
|
40
63
|
self.__private_name: Optional[str] = None
|
41
64
|
self._check = check_types
|
42
65
|
|
@@ -70,7 +93,9 @@ class Column[TProp]:
|
|
70
93
|
def __hash__(self) -> int:
|
71
94
|
return hash(
|
72
95
|
(
|
96
|
+
self.dtype,
|
73
97
|
self.column_name,
|
98
|
+
self.table,
|
74
99
|
self.is_primary_key,
|
75
100
|
self.is_auto_generated,
|
76
101
|
self.is_auto_increment,
|
ormlambda/sql/foreign_key.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from typing import Callable, TYPE_CHECKING, Optional, Any, Type, overload
|
2
|
+
from typing import Callable, TYPE_CHECKING, Optional, Any, Type, cast, overload
|
3
3
|
|
4
4
|
from ormlambda.common.interfaces.IQueryCommand import IQuery
|
5
5
|
|
@@ -10,15 +10,45 @@ if TYPE_CHECKING:
|
|
10
10
|
from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
|
11
11
|
|
12
12
|
|
13
|
+
class ForeignKeyContext(set["ForeignKey"]):
|
14
|
+
def clear(self):
|
15
|
+
to_remove = {x for x in self if not cast(ForeignKey, x)._keep_alive}
|
16
|
+
for el in to_remove:
|
17
|
+
self.remove(el)
|
18
|
+
|
19
|
+
def remove(self, element):
|
20
|
+
return super().remove(element)
|
21
|
+
|
22
|
+
def pop(self, item):
|
23
|
+
for el in self:
|
24
|
+
if el != item:
|
25
|
+
continue
|
26
|
+
|
27
|
+
if not cast(ForeignKey, el)._keep_alive:
|
28
|
+
super().remove(el)
|
29
|
+
return el
|
30
|
+
|
31
|
+
def add(self, element):
|
32
|
+
return super().add(element)
|
33
|
+
|
34
|
+
|
13
35
|
class ForeignKey[TLeft: Table, TRight: Table](IQuery):
|
14
|
-
stored_calls:
|
36
|
+
stored_calls: ForeignKeyContext = ForeignKeyContext()
|
15
37
|
|
16
38
|
@overload
|
17
39
|
def __new__[LProp, RProp](self, comparer: Comparer[LProp, RProp], clause_name: str) -> None: ...
|
18
40
|
@overload
|
19
|
-
def __new__[LProp, TRight, RProp](cls, tright: Type[TRight], relationship: Callable[[TLeft, TRight], Any | Comparer[TLeft, LProp, TRight, RProp]]) -> TRight: ...
|
41
|
+
def __new__[LProp, TRight, RProp](cls, tright: Type[TRight], relationship: Callable[[TLeft, TRight], Any | Comparer[TLeft, LProp, TRight, RProp]], keep_alive: bool = ...) -> TRight: ...
|
20
42
|
|
21
|
-
def __new__[LProp, TRight, RProp](
|
43
|
+
def __new__[LProp, TRight, RProp](
|
44
|
+
cls,
|
45
|
+
tright: Optional[TRight] = None,
|
46
|
+
relationship: Optional[Callable[[TLeft, TRight], Any | Comparer[TLeft, LProp, TRight, RProp]]] = None,
|
47
|
+
*,
|
48
|
+
comparer: Optional[Comparer] = None,
|
49
|
+
clause_name: Optional[str] = None,
|
50
|
+
keep_alive: bool = False,
|
51
|
+
) -> TRight:
|
22
52
|
return super().__new__(cls)
|
23
53
|
|
24
54
|
def __init__[LProp, RProp](
|
@@ -28,7 +58,9 @@ class ForeignKey[TLeft: Table, TRight: Table](IQuery):
|
|
28
58
|
*,
|
29
59
|
comparer: Optional[Comparer] = None,
|
30
60
|
clause_name: Optional[str] = None,
|
61
|
+
keep_alive: bool = False,
|
31
62
|
) -> None:
|
63
|
+
self._keep_alive = keep_alive
|
32
64
|
if comparer is not None and clause_name is not None:
|
33
65
|
self.__init__with_comparer(comparer, clause_name)
|
34
66
|
else:
|
@@ -27,6 +27,7 @@ from ..types import (
|
|
27
27
|
Select10,
|
28
28
|
TypeExists,
|
29
29
|
WhereTypes,
|
30
|
+
SelectCols,
|
30
31
|
)
|
31
32
|
|
32
33
|
|
@@ -130,12 +131,12 @@ class IStatements[T: Table](ABC):
|
|
130
131
|
# endregion
|
131
132
|
# region count
|
132
133
|
@abstractmethod
|
133
|
-
def count(
|
134
|
+
def count[TProp](
|
134
135
|
self,
|
135
|
-
selection:
|
136
|
-
|
136
|
+
selection: None | SelectCols[T, TProp] = ...,
|
137
|
+
alias: str = ...,
|
137
138
|
execute: bool = False,
|
138
|
-
) -> Optional[
|
139
|
+
) -> Optional[int]: ...
|
139
140
|
|
140
141
|
# endregion
|
141
142
|
# region delete
|
@@ -161,46 +162,52 @@ class IStatements[T: Table](ABC):
|
|
161
162
|
def where[LProp, RTable, RProp](self, conditions: WhereTypes[T, LProp, RTable, RProp] = None) -> IStatements[T]: ...
|
162
163
|
|
163
164
|
# endregion
|
164
|
-
|
165
|
-
|
166
|
-
|
165
|
+
|
166
|
+
# region having
|
167
|
+
|
167
168
|
@overload
|
168
|
-
def
|
169
|
+
def having[LProp, RTable, RProp](self, conditions: Callable[[T], WhereTypes[T, LProp, RTable, RProp]]) -> IStatements[T]: ...
|
170
|
+
|
169
171
|
@abstractmethod
|
170
|
-
def
|
172
|
+
def having[LProp, RTable, RProp](self, conditions: WhereTypes[T, LProp, RTable, RProp] = None) -> IStatements[T]: ...
|
173
|
+
|
174
|
+
# endregion
|
175
|
+
# region order
|
176
|
+
@abstractmethod
|
177
|
+
def order[TValue](self, columns: SelectCols[T, TValue], order_type: OrderTypes) -> IStatements[T]: ...
|
171
178
|
|
172
179
|
# endregion
|
173
180
|
# region concat
|
174
181
|
@overload
|
175
|
-
def concat
|
182
|
+
def concat(self, selector: SelectCols[T, str], alias: str = "concat") -> IAggregate: ...
|
176
183
|
|
177
184
|
# endregion
|
178
185
|
# region max
|
179
|
-
@
|
186
|
+
@abstractmethod
|
180
187
|
def max[TProp](
|
181
188
|
self,
|
182
|
-
column:
|
189
|
+
column: SelectCols[T, TProp],
|
183
190
|
alias: Optional[str] = ...,
|
184
|
-
execute: bool =
|
185
|
-
) ->
|
191
|
+
execute: bool = False,
|
192
|
+
) -> int: ...
|
186
193
|
# endregion
|
187
194
|
# region min
|
188
|
-
@
|
195
|
+
@abstractmethod
|
189
196
|
def min[TProp](
|
190
197
|
self,
|
191
|
-
column:
|
198
|
+
column: SelectCols[T, TProp],
|
192
199
|
alias: Optional[str] = ...,
|
193
|
-
execute: bool =
|
194
|
-
) ->
|
200
|
+
execute: bool = False,
|
201
|
+
) -> int: ...
|
195
202
|
# endregion
|
196
203
|
# region sum
|
197
|
-
@
|
204
|
+
@abstractmethod
|
198
205
|
def sum[TProp](
|
199
206
|
self,
|
200
|
-
column:
|
207
|
+
column: SelectCols[T, TProp],
|
201
208
|
alias: Optional[str] = ...,
|
202
|
-
execute: bool =
|
203
|
-
) ->
|
209
|
+
execute: bool = False,
|
210
|
+
) -> int: ...
|
204
211
|
|
205
212
|
@overload
|
206
213
|
def join[FKTable](self, joins: TupleJoinType[FKTable] | tuple[*TupleJoinType[FKTable]]) -> JoinContext[tuple[*TupleJoinType[FKTable]]]: ...
|
@@ -208,6 +215,8 @@ class IStatements[T: Table](ABC):
|
|
208
215
|
# endregion
|
209
216
|
# region select
|
210
217
|
type SelectorType[TOri, *T] = Callable[[TOri], tuple[*T]] | tuple[*T]
|
218
|
+
type SelectorFlavourType[T, TResponse] = Optional[Callable[[T], TResponse]] | TResponse
|
219
|
+
type SelectorOneType[T, TResponse] = Callable[[T, TResponse]] | TResponse
|
211
220
|
|
212
221
|
@overload
|
213
222
|
def select[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](self, selector: SelectorType[T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], *, by: Optional[Enum] = ...) -> Select10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]: ...
|
@@ -234,8 +243,6 @@ class IStatements[T: Table](ABC):
|
|
234
243
|
@overload
|
235
244
|
def select(self) -> Tuple[T]: ...
|
236
245
|
|
237
|
-
type SelectorFlavourType[T, TResponse] = Optional[Callable[[T], TResponse]]
|
238
|
-
|
239
246
|
# @overload
|
240
247
|
# def select[TFlavour](self, selector: Optional[Callable[[T], tuple]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour], by: Optional[Enum] = ..., **kwargs) -> TFlavour: ...
|
241
248
|
@overload
|
@@ -243,7 +250,7 @@ class IStatements[T: Table](ABC):
|
|
243
250
|
@overload
|
244
251
|
def select[*TRes](self, selector: SelectorFlavourType[T, tuple[*TRes]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., **kwargs) -> tuple[tuple[*TRes]]: ...
|
245
252
|
@overload
|
246
|
-
def select[TFlavour](self, selector: SelectorFlavourType[T, tuple] = ..., *, flavour: Type[TFlavour], by: Optional[Enum] = ..., **kwargs) -> tuple[TFlavour]: ...
|
253
|
+
def select[TFlavour](self, selector: SelectorFlavourType[T, tuple] = ..., *, flavour: Type[TFlavour], by: Optional[Enum] = ..., **kwargs) -> tuple[TFlavour, ...]: ...
|
247
254
|
|
248
255
|
@abstractmethod
|
249
256
|
def select[TValue, TFlavour, P](self, selector: SelectorFlavourType[T, tuple[TValue, P]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour] = ..., by: JoinType = ..., **kwargs): ...
|
@@ -255,21 +262,21 @@ class IStatements[T: Table](ABC):
|
|
255
262
|
@overload
|
256
263
|
def select_one[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
|
257
264
|
@overload
|
258
|
-
def select_one[T1](self, selector:
|
265
|
+
def select_one[T1](self, selector: SelectorOneType[T, T1 | tuple[T1]], *, by: Optional[Enum] = ...) -> T1: ...
|
259
266
|
@overload
|
260
|
-
def select_one[*TRes](self, selector:
|
267
|
+
def select_one[*TRes](self, selector: SelectorOneType[T, tuple[*TRes]], *, by: Optional[Enum] = ...) -> tuple[*TRes]: ...
|
261
268
|
@overload
|
262
|
-
def select_one[T1](self, selector:
|
269
|
+
def select_one[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, **kwargs) -> T1: ...
|
263
270
|
@overload
|
264
|
-
def select_one[T1, TFlavour](self, selector:
|
271
|
+
def select_one[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
|
265
272
|
@overload
|
266
|
-
def select_one[*TRest](self, selector:
|
273
|
+
def select_one[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], **kwargs) -> tuple[*TRest]: ...
|
267
274
|
@overload
|
268
|
-
def select_one[TFlavour](self, selector:
|
275
|
+
def select_one[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
|
269
276
|
@abstractmethod
|
270
277
|
def select_one[TValue, TFlavour, *TRest](
|
271
278
|
self,
|
272
|
-
selector: Optional[
|
279
|
+
selector: Optional[SelectorOneType[T, tuple[TValue, *TRest]]] = lambda: None,
|
273
280
|
*,
|
274
281
|
flavour: Type[TFlavour] = ...,
|
275
282
|
by: Optional[Enum] = ...,
|
@@ -281,23 +288,23 @@ class IStatements[T: Table](ABC):
|
|
281
288
|
@overload
|
282
289
|
def first(self) -> T: ...
|
283
290
|
@overload
|
284
|
-
def first[
|
291
|
+
def first[T1](self, selector: SelectorOneType[T, T1 | tuple[T1]], *, by: Optional[Enum] = ...) -> T1: ...
|
285
292
|
@overload
|
286
|
-
def first[
|
293
|
+
def first[*TRes](self, selector: SelectorOneType[T, tuple[*TRes]], *, by: Optional[Enum] = ...) -> tuple[*TRes]: ...
|
287
294
|
@overload
|
288
|
-
def first[
|
295
|
+
def first[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
|
289
296
|
@overload
|
290
|
-
def first[T1](self, selector:
|
297
|
+
def first[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, **kwargs) -> T1: ...
|
291
298
|
@overload
|
292
|
-
def first[T1, TFlavour](self, selector:
|
299
|
+
def first[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
|
293
300
|
@overload
|
294
|
-
def first[*TRest](self, selector:
|
301
|
+
def first[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], **kwargs) -> tuple[*TRest]: ...
|
295
302
|
@overload
|
296
|
-
def first[TFlavour](self, selector:
|
303
|
+
def first[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
|
297
304
|
@abstractmethod
|
298
305
|
def first[TValue, TFlavour, *TRest](
|
299
306
|
self,
|
300
|
-
selector: Optional[
|
307
|
+
selector: Optional[SelectorOneType[T, tuple[TValue, *TRest]]] = lambda: None,
|
301
308
|
*,
|
302
309
|
flavour: Type[TFlavour] = ...,
|
303
310
|
by: Optional[Enum] = ...,
|
@@ -305,9 +312,9 @@ class IStatements[T: Table](ABC):
|
|
305
312
|
|
306
313
|
# endregion
|
307
314
|
|
308
|
-
# region
|
315
|
+
# region groupby
|
309
316
|
@abstractmethod
|
310
|
-
def
|
317
|
+
def groupby[TRepo](self, column: Callable[[T], TRepo]) -> IStatements[T]: ...
|
311
318
|
|
312
319
|
# endregion
|
313
320
|
|
ormlambda/statements/types.py
CHANGED
@@ -10,15 +10,18 @@ from typing import (
|
|
10
10
|
import enum
|
11
11
|
|
12
12
|
|
13
|
-
from ormlambda.common.enums import JoinType
|
14
|
-
|
15
13
|
if TYPE_CHECKING:
|
14
|
+
from ormlambda.common.enums import JoinType
|
16
15
|
from ormlambda.sql.comparer import Comparer
|
16
|
+
from ormlambda.sql.types import ColumnType
|
17
17
|
|
18
18
|
type OrderTypes = Literal["ASC", "DESC"] | OrderType | Iterable[OrderType]
|
19
19
|
|
20
20
|
|
21
|
-
class OrderType(enum.Enum):
|
21
|
+
class OrderType(str, enum.Enum):
|
22
|
+
def __str__(self):
|
23
|
+
return super().__str__()
|
24
|
+
|
22
25
|
ASC = "ASC"
|
23
26
|
DESC = "DESC"
|
24
27
|
|
@@ -49,3 +52,6 @@ type WhereTypes[LTable, LProp, RTable, RProp] = Union[
|
|
49
52
|
tuple[Comparer[LTable, LProp, RTable, RProp], ...],
|
50
53
|
Callable[[LTable], WhereTypes[LTable, LProp, RTable, RProp]],
|
51
54
|
]
|
55
|
+
|
56
|
+
|
57
|
+
type SelectCols[T, TProp] = Callable[[T], ColumnType[TProp]] | ColumnType[TProp]
|
@@ -1,15 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ormlambda
|
3
|
-
Version: 3.
|
3
|
+
Version: 3.11.1
|
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 (==4.3.1)
|
11
10
|
Requires-Dist: mysql-connector-python (>=9.0.0,<10.0.0)
|
12
|
-
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
13
11
|
Requires-Dist: shapely (>=2.0.6,<3.0.0)
|
14
12
|
Description-Content-Type: text/markdown
|
15
13
|
|
@@ -17,7 +15,7 @@ Description-Content-Type: text/markdown
|
|
17
15
|

|
18
16
|

|
19
17
|
|
20
|
-
#
|
18
|
+
# ormlambda Documentation
|
21
19
|
This ORM is designed to connect with a MySQL server, facilitating the management of various database queries. Built with flexibility and efficiency in mind, this ORM empowers developers to interact with the database using lambda functions, allowing for concise and expressive query construction.
|
22
20
|
|
23
21
|
# Creating your first lambda query
|
@@ -38,19 +36,34 @@ database = MySQLRepository(user=USERNAME, password=PASSWORD, database="sakila",
|
|
38
36
|
## Select all columns
|
39
37
|
```python
|
40
38
|
from ormlambda import ORM
|
41
|
-
from ormlambda
|
39
|
+
from ormlambda import create_engine
|
42
40
|
|
43
41
|
from models.address import Address
|
44
|
-
from config import config_dict
|
42
|
+
from test.config import config_dict
|
45
43
|
|
46
|
-
db =
|
44
|
+
db = create_engine('mysql://root:1234@localhost:3306/sakila')
|
47
45
|
|
48
|
-
AddressModel = ORM(Address,db)
|
46
|
+
AddressModel = ORM(Address, db)
|
49
47
|
|
50
48
|
result = AddressModel.select()
|
51
49
|
```
|
52
50
|
The `result` var will be of type `tuple[Address, ...]`
|
53
51
|
|
52
|
+
## Improving Typing
|
53
|
+
For those cases where you need to pass the database configuration from a `dict`, you can use `MySQLArgs` TypedDict object to improve type annotations.
|
54
|
+
|
55
|
+
```python
|
56
|
+
from ormlambda.databases.my_sql.types import MySQLArgs
|
57
|
+
|
58
|
+
config_dict: MySQLArgs = {
|
59
|
+
"user": DB_USERNAME,
|
60
|
+
"password": DB_PASSWORD,
|
61
|
+
"host": DB_HOST,
|
62
|
+
"database": DB_DATABASE,
|
63
|
+
}
|
64
|
+
db = MySQLRepository(**config_dict)
|
65
|
+
```
|
66
|
+
|
54
67
|
## Select multiples tables
|
55
68
|
Once the `AddressModel` class is created, we will not only be able to access all the information in that table, but also all the information in all the tables that have foreign keys related to it."
|
56
69
|
|
@@ -296,6 +309,92 @@ res = AddressModel.sum(Address.address_id, execute=True)
|
|
296
309
|
res = AddressModel.count(Address.address_id, execute=True)
|
297
310
|
```
|
298
311
|
|
312
|
+
## 1. Concat
|
313
|
+
|
314
|
+
The `concat` method allows you to concatenate multiple columns or values into a single string. This is particularly useful for creating derived fields in your queries.
|
315
|
+
|
316
|
+
#### Usage
|
317
|
+
|
318
|
+
```python
|
319
|
+
response = ORM(Address, db).where(Address.City.Country.country.regex(r"^Spain")).first(
|
320
|
+
(
|
321
|
+
Address.address,
|
322
|
+
Address.City.city,
|
323
|
+
self.tmodel.concat(
|
324
|
+
(
|
325
|
+
"Address: ",
|
326
|
+
Address.address,
|
327
|
+
" - city: ",
|
328
|
+
Address.City.city,
|
329
|
+
" - country: ",
|
330
|
+
Address.City.Country.country,
|
331
|
+
)
|
332
|
+
),
|
333
|
+
),
|
334
|
+
flavour=dict,
|
335
|
+
)
|
336
|
+
|
337
|
+
{
|
338
|
+
"address_address": "939 Probolinggo Loop",
|
339
|
+
"city_city": "A Coruña (La Coruña)",
|
340
|
+
"CONCAT": "Address: 939 Probolinggo Loop - city: A Coruña (La Coruña) - country: Spain",
|
341
|
+
}
|
342
|
+
```
|
343
|
+
As you can see in the response, the result is a dictionary where the keys are a combination of the table name and the column name. This is done to avoid collisions with columns from other tables that might have the same name.
|
344
|
+
|
345
|
+
Another elegant approach to adjust the response and obtain an object is by using the `flavour` attribute. You can pass a callable object, which will be used to instantiate it with the returned data.
|
346
|
+
|
347
|
+
## Using BaseModel for Custom Responses (Pydantic)
|
348
|
+
|
349
|
+
You can utilize `BaseModel` from Pydantic to create structured response models. This allows you to define the expected structure of your data, ensuring type safety and validation.
|
350
|
+
|
351
|
+
### Example: Creating a Custom Response Model
|
352
|
+
|
353
|
+
You can create a custom response model by subclassing `BaseModel`. In this model, you define the fields that you expect in your response, along with their types.
|
354
|
+
|
355
|
+
```python
|
356
|
+
class AddressCombine(BaseModel):
|
357
|
+
address: str
|
358
|
+
city: str
|
359
|
+
country: str
|
360
|
+
|
361
|
+
model_config: ConfigDict = {"extra": "forbid"}
|
362
|
+
|
363
|
+
ddbb = MySQLRepository(**config_dict)
|
364
|
+
model = ORM(Address, ddbb)
|
365
|
+
select = (
|
366
|
+
model.order(lambda x: x.City.Country.country, "DESC")
|
367
|
+
.limit(10)
|
368
|
+
.where(Address.City.Country.country == "Spain")
|
369
|
+
.first(
|
370
|
+
lambda x: (
|
371
|
+
x.address,
|
372
|
+
x.City.city,
|
373
|
+
x.City.Country.country,
|
374
|
+
),
|
375
|
+
flavour=AddressCombine,
|
376
|
+
)
|
377
|
+
)
|
378
|
+
```
|
379
|
+
|
380
|
+
Once you execute the query, the result will be an instance of your custom model. You can access the fields directly, ensuring that the data adheres to the structure you defined.
|
381
|
+
|
382
|
+
```python
|
383
|
+
|
384
|
+
|
385
|
+
print(select.address)
|
386
|
+
print(select.city)
|
387
|
+
print(select.country)
|
388
|
+
```
|
389
|
+
|
390
|
+
|
391
|
+
<!-- ### 2. Having
|
392
|
+
|
393
|
+
The `having` method is used to filter results based on aggregate functions. It is typically used in conjunction with `group by` clauses.
|
394
|
+
|
395
|
+
#### Usage -->
|
396
|
+
|
397
|
+
|
299
398
|
## Combine aggregation method
|
300
399
|
As shown in the previous examples, setting the `execute` attribute to `True` allows us to perform the corresponding query in a single line. However, if you're looking to improve efficiency, you can combine all of them into one query.
|
301
400
|
```python
|
@@ -1,4 +1,4 @@
|
|
1
|
-
ormlambda/__init__.py,sha256=
|
1
|
+
ormlambda/__init__.py,sha256=NKN-ggMFCOE4Zhir1cfFEf6c19hdPol_zWI6Fj5-h30,673
|
2
2
|
ormlambda/caster/__init__.py,sha256=JWJ6qdPTk_uyJHGfFpvFCZeOXdP6DzL4-MtMFZVDPRY,150
|
3
3
|
ormlambda/caster/base_caster.py,sha256=c3vCGoKDyJ39kfUiS7sNKhKdjBRYSK1Ie88lwDIXqgE,1774
|
4
4
|
ormlambda/caster/caster.py,sha256=ecDvGgMI3yFtJxqKD9XcSVtBcqQtYitfMTooWPlLnEY,1885
|
@@ -38,7 +38,7 @@ ormlambda/components/upsert/abstract_upsert.py,sha256=a5_dJxTKI6GtxNTesxKtGFyy-A
|
|
38
38
|
ormlambda/databases/__init__.py,sha256=-m7uIigkbFNU5JHeOE8DeTA2bRVYEppw2XPASTSvW_o,136
|
39
39
|
ormlambda/databases/my_sql/__init__.py,sha256=2Ue97WtcpfB6-8SgUIHLOzk_iT44YUzG6baXCHmV9uA,212
|
40
40
|
ormlambda/databases/my_sql/caster/__init__.py,sha256=Df2sdZaAJ1Mi5Ego0sILMk5pF1NbK-nlV0hbpzd0PWE,47
|
41
|
-
ormlambda/databases/my_sql/caster/caster.py,sha256=
|
41
|
+
ormlambda/databases/my_sql/caster/caster.py,sha256=6byP5RJsWmnLZ2C9Br8OpdpilLedogDlTv3i8HMObu8,1217
|
42
42
|
ormlambda/databases/my_sql/caster/read.py,sha256=PBseYoNJtMgmr4sL5aD6uef0f-mm6LakAz-v-IcBs7w,1096
|
43
43
|
ormlambda/databases/my_sql/caster/types/__init__.py,sha256=lZ9YFqDjY6d6-Vy0tBMZfLI5EhyKXrb12Ys4eYiWjAg,396
|
44
44
|
ormlambda/databases/my_sql/caster/types/bytes.py,sha256=Aq4iO-JmHeCXLqcQfNqsSTUpc1gceqY3TC4H3PJfv3g,899
|
@@ -52,39 +52,43 @@ ormlambda/databases/my_sql/caster/types/string.py,sha256=uYIfXHLrXhiShd9KRALBc2U
|
|
52
52
|
ormlambda/databases/my_sql/caster/write.py,sha256=mfbtlAFamsnMbe1L4ARSAw2ch5qhz15jh5cSyAljcss,1322
|
53
53
|
ormlambda/databases/my_sql/clauses/ST_AsText.py,sha256=Fx-CgQ01aSkcuSlcdmLIWb7f3kd7r6kWs_BGu1HOVx8,1165
|
54
54
|
ormlambda/databases/my_sql/clauses/ST_Contains.py,sha256=K9cZwQaQQCgZTQdnAokln5lVSyV99CkeRnmOd2RIots,968
|
55
|
-
ormlambda/databases/my_sql/clauses/__init__.py,sha256=
|
56
|
-
ormlambda/databases/my_sql/clauses/alias.py,sha256=
|
55
|
+
ormlambda/databases/my_sql/clauses/__init__.py,sha256=H1DDCYiqAhrxXgovUaju5tsgLv8kU6y8Lh6vZO9uHTM,863
|
56
|
+
ormlambda/databases/my_sql/clauses/alias.py,sha256=Xo0zQwyza3SMMRPIlBJWDQAJdW3bHjrC_UDps26P-QU,989
|
57
57
|
ormlambda/databases/my_sql/clauses/count.py,sha256=rh7KNzpxkKEZpqmFV0oc8xHVgOHVGTGHrPGmCF-eLB4,1384
|
58
58
|
ormlambda/databases/my_sql/clauses/create_database.py,sha256=zpd8uosxKJsf9BULvAHSd1-fU5de8OI7WRqVa8oyiA4,1209
|
59
59
|
ormlambda/databases/my_sql/clauses/delete.py,sha256=Vm9lRKuX9x_m8faTlOs_A3v9zzoGGCnQ7CH_-QM6uK4,1900
|
60
60
|
ormlambda/databases/my_sql/clauses/drop_database.py,sha256=2GYhtWzHSWM7Yy3v_l2hiY4fFumG8DSCGGLgP0t3Rhk,437
|
61
61
|
ormlambda/databases/my_sql/clauses/drop_table.py,sha256=ltaJJFcNXChBF7fYGNCZK9QQ4iWfG72HFacL57f2k6A,569
|
62
|
-
ormlambda/databases/my_sql/clauses/group_by.py,sha256=
|
62
|
+
ormlambda/databases/my_sql/clauses/group_by.py,sha256=m-Q6GjhjAx5Y1hH3bGmWOIvdMSE_ilEY8YNCV7fqT5g,849
|
63
|
+
ormlambda/databases/my_sql/clauses/having.py,sha256=yfRJP3Zw4JEdQPkJtqQ4cZwxcUJTBLlb4e7nTRMaUSk,400
|
63
64
|
ormlambda/databases/my_sql/clauses/insert.py,sha256=xR9IRiJeTIw-65MhnbK_uemMdvIEAaqFPg4IFBtC9Yk,3691
|
64
65
|
ormlambda/databases/my_sql/clauses/joins.py,sha256=PEq7_qxgjJK5R_m8WkqJWppEc-bQFIbAb88qn81uGOg,5170
|
65
66
|
ormlambda/databases/my_sql/clauses/limit.py,sha256=32Fii_WHjrX7K5B7H5uWlzYM6KBMFsE-Uz-70CEvTok,386
|
66
67
|
ormlambda/databases/my_sql/clauses/offset.py,sha256=PKieZvCYLSSza-Nhcam5DJEYv--jBU8RHwju3P_f9Kk,390
|
67
|
-
ormlambda/databases/my_sql/clauses/order.py,sha256=
|
68
|
+
ormlambda/databases/my_sql/clauses/order.py,sha256=n4vrssvUH9e8vlDHvML6Bclw6KHurkWePQ_WZavVxRE,2316
|
68
69
|
ormlambda/databases/my_sql/clauses/select.py,sha256=O1dZWKG3_93-s_X_EjOF_alp_U82EzfDUKBMBcajxKY,1830
|
69
70
|
ormlambda/databases/my_sql/clauses/update.py,sha256=GAXqEPEnUUO-M1zlaTU1Esso0s6lL7nmZWSEErZK2iE,2940
|
70
71
|
ormlambda/databases/my_sql/clauses/upsert.py,sha256=VJAwfvpIT3xXwm3AnifVqiswnYNleDTnbY0CgnQqC0s,1945
|
71
|
-
ormlambda/databases/my_sql/clauses/where.py,sha256=
|
72
|
+
ormlambda/databases/my_sql/clauses/where.py,sha256=IIyXt98S_ExpC0IHqEO2OL1j-VK9An3Kkbsd2t-2OQU,1694
|
72
73
|
ormlambda/databases/my_sql/functions/__init__.py,sha256=hA8t3mUpV2p-pO4TVp5rjC5Yp7aIkWPsS8NpLi3DUh0,171
|
73
|
-
ormlambda/databases/my_sql/functions/concat.py,sha256=
|
74
|
-
ormlambda/databases/my_sql/functions/max.py,sha256=
|
74
|
+
ormlambda/databases/my_sql/functions/concat.py,sha256=jGUQEj28Gh89ilwJqwFpP5mXyw9tvZ4iC2DrvS4X25M,1346
|
75
|
+
ormlambda/databases/my_sql/functions/max.py,sha256=AjROl4V9RYPMQoo0TomoTB8fRiMyN5-n6hTGRT_G-pY,1461
|
75
76
|
ormlambda/databases/my_sql/functions/min.py,sha256=9g8twv0wUfpxrRK2socnfkJtmd_78pU6HDk_4AiV03c,1487
|
76
77
|
ormlambda/databases/my_sql/functions/sum.py,sha256=PUItqZ4ZbBcOfPzGbYDVvhVKV1RxLMuI63xNbSD8KrA,1487
|
77
|
-
ormlambda/databases/my_sql/join_context.py,sha256=
|
78
|
+
ormlambda/databases/my_sql/join_context.py,sha256=SLxVSwCURLOBSMB-aN7PV69sBQXOOP1sCezAKn3Wnqo,3256
|
78
79
|
ormlambda/databases/my_sql/repository/__init__.py,sha256=_T7m-UpgJlx7eYdjBw8jdSVFGnjFYAcbp45g4EM7YEk,54
|
79
|
-
ormlambda/databases/my_sql/repository/repository.py,sha256=
|
80
|
-
ormlambda/databases/my_sql/statements.py,sha256=
|
80
|
+
ormlambda/databases/my_sql/repository/repository.py,sha256=DXxY1I4NMA7zshWpzSc6TKf3RlNsOfdk_DDjCF7PoxQ,12149
|
81
|
+
ormlambda/databases/my_sql/statements.py,sha256=9mqKSVsgceRc666aG56CoJsUu5zI5LAg0CWmeRQK928,17280
|
81
82
|
ormlambda/databases/my_sql/types.py,sha256=6c7LMS1VGR8ko1LB1T8DQzn1l10Mzk8PfIeYEOb9w30,1839
|
82
|
-
ormlambda/engine/__init__.py,sha256=
|
83
|
+
ormlambda/engine/__init__.py,sha256=tTA0VcN-kxpmnTS0smq7IK0ohGVwpM5TIju-sDnZhfk,82
|
84
|
+
ormlambda/engine/create.py,sha256=HwtLi9T_Z7mnZIPfSmutRPT7SlIDFfs82oJuVe-pObo,955
|
83
85
|
ormlambda/engine/template.py,sha256=colmdl-IBSGc1eIqIYShsVkseQwF5_gwwc6Pt8ndN24,1350
|
86
|
+
ormlambda/engine/url.py,sha256=4FnkQQO93jQcGWmZF38DiJgIrRcIgIYacy2N6Dy3YX8,25401
|
87
|
+
ormlambda/engine/utils.py,sha256=fFoiKsiFuLcjcBVYNebVoYnMrEj3aZdoxEVSNfCY-GM,522
|
84
88
|
ormlambda/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
85
89
|
ormlambda/model/base_model.py,sha256=S_PYs5ZO-LTgiJSyAmGUtXwFKLb9VnM2Rqlq4pdhppY,1021
|
86
90
|
ormlambda/repository/__init__.py,sha256=4KAhKn6vWV7bslewvGMNqbbbUnz1DLnH4yy-M5QNAQA,112
|
87
|
-
ormlambda/repository/base_repository.py,sha256=
|
91
|
+
ormlambda/repository/base_repository.py,sha256=5PeMcBMFGmdTlob-M2_iX1PJ1sNZa3mimx9fWgOuiTM,422
|
88
92
|
ormlambda/repository/interfaces/IDatabaseConnection.py,sha256=pxczjx0b53yjjg5hvVDloMgUTFDahVC3HlJLQjo9_1w,283
|
89
93
|
ormlambda/repository/interfaces/IRepositoryBase.py,sha256=24AFQ9ZBnFBQtdt3nkyFXkUbEzEsD2P7OS0FnFECJB8,1206
|
90
94
|
ormlambda/repository/interfaces/__init__.py,sha256=t8Mn0aRZm8uF4MGaqjEANTTADCdOwNF0THZ_qebyzwo,126
|
@@ -94,10 +98,10 @@ ormlambda/sql/clause_info/clause_info.py,sha256=V4IQ6fuqf0Y-AS0qykQNcpOA2joib3FL
|
|
94
98
|
ormlambda/sql/clause_info/clause_info_context.py,sha256=Y32p3x4mqcdNHbAowrKaN_ldnGn7zvaP1UdAkWWryhM,2852
|
95
99
|
ormlambda/sql/clause_info/interface/IAggregate.py,sha256=P-QPaTMAMHVR5M9-ClmL8wsj0uNGG5xpxjuAwWnzKxA,216
|
96
100
|
ormlambda/sql/clause_info/interface/__init__.py,sha256=7eEyHO7P_1DB63bP0ej5EjKkvb7IHwaGlSG58Hrv2X0,49
|
97
|
-
ormlambda/sql/column.py,sha256=
|
101
|
+
ormlambda/sql/column.py,sha256=pFCvJKiL4On1VVX41IutGq9eC60xf6Dd8zpXPRMDdFE,5978
|
98
102
|
ormlambda/sql/comparer.py,sha256=XTi4QT2ICtssCPsF8yrMwLDswnu7lF3MO217hAAY0t8,5334
|
99
103
|
ormlambda/sql/dtypes.py,sha256=Ji4QOyKD0n9bKe7yXIIduy9uEX5BaXolQSIsx0NXYJY,7843
|
100
|
-
ormlambda/sql/foreign_key.py,sha256=
|
104
|
+
ormlambda/sql/foreign_key.py,sha256=lz5TiHmPFKdfL7ESwUt_MnUy2XYUTiOUiQtammoQTwQ,5530
|
101
105
|
ormlambda/sql/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
102
106
|
ormlambda/sql/table/__init__.py,sha256=nAHXi63eDJeGGCf4f0A7W6x4Rh3FJ2dpfzxPEN6r3bc,62
|
103
107
|
ormlambda/sql/table/fields.py,sha256=ovNR3bJ473aKW-2NhbKr0iJlVpgW06jurHLob2IyZU8,2116
|
@@ -105,14 +109,14 @@ ormlambda/sql/table/table_constructor.py,sha256=_sc1WnhnjchvIzxQZ85qZJFGZExlmhgK
|
|
105
109
|
ormlambda/sql/types.py,sha256=z5FME0m9j7zSKlxS21cZxHRg0pyTfiJbq7VWZ6IT0kM,832
|
106
110
|
ormlambda/statements/__init__.py,sha256=mFER-VoLf5L2BjdQhWMw6rVQi8kpr-qZzi1ZSWRPIIU,99
|
107
111
|
ormlambda/statements/base_statement.py,sha256=WLjQrWw72NhBdNkP8uO1UP8hzfv-leyFjmMa4ofa-fk,5660
|
108
|
-
ormlambda/statements/interfaces/IStatements.py,sha256=
|
112
|
+
ormlambda/statements/interfaces/IStatements.py,sha256=GhaC7KpQJT1i0vAZjreIN91H6PiNWvhmDt77ZWHxdW4,11731
|
109
113
|
ormlambda/statements/interfaces/__init__.py,sha256=a3RyTNVA7DwWMqvVi7gFYP4MArdU-RUYixJcxfc79HY,76
|
110
|
-
ormlambda/statements/types.py,sha256=
|
114
|
+
ormlambda/statements/types.py,sha256=0AYnj6WCQcS-4fhsaK_yu2zQR3guPhPluq_sZxH1UhQ,1938
|
111
115
|
ormlambda/utils/__init__.py,sha256=SEgDWkwbSrYRv0If92Ewq53DKnxxv5HqEAQbETd1C6Q,50
|
112
116
|
ormlambda/utils/module_tree/__init__.py,sha256=LNQtqkwO1ul49Th3aHAIiyt0Wt899GmXCc44Uz1eDyY,53
|
113
117
|
ormlambda/utils/module_tree/dfs_traversal.py,sha256=lSF03G63XtJFLp03ueAmsHMBvhUkjptDbK3IugXm8iU,1425
|
114
118
|
ormlambda/utils/module_tree/dynamic_module.py,sha256=SJWpOC5oqASGjCXYHW0JwzEpcZ_DkxKLyK4SpIsMbaA,8700
|
115
|
-
ormlambda-3.
|
116
|
-
ormlambda-3.
|
117
|
-
ormlambda-3.
|
118
|
-
ormlambda-3.
|
119
|
+
ormlambda-3.11.1.dist-info/LICENSE,sha256=xBprFw8GJLdHMOoUqDk0427EvjIcbEREvXXVFULuuXU,1080
|
120
|
+
ormlambda-3.11.1.dist-info/METADATA,sha256=heOegmWNeP8I61l3pjhm6Gchi494A0CTTGoX6HPtgnc,12450
|
121
|
+
ormlambda-3.11.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
122
|
+
ormlambda-3.11.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|