ormlambda 4.0.0__py3-none-any.whl → 4.0.5__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/dialects/__init__.py +11 -4
- ormlambda/dialects/default/base.py +3 -2
- ormlambda/dialects/mysql/base.py +4 -1
- ormlambda/engine/base.py +15 -2
- ormlambda/engine/create.py +6 -1
- ormlambda/repository/base_repository.py +4 -0
- ormlambda/repository/response.py +9 -1
- ormlambda/statements/base_statement.py +38 -43
- ormlambda/statements/interfaces/IStatements.py +4 -4
- ormlambda/statements/statements.py +3 -6
- {ormlambda-4.0.0.dist-info → ormlambda-4.0.5.dist-info}/METADATA +35 -55
- {ormlambda-4.0.0.dist-info → ormlambda-4.0.5.dist-info}/RECORD +15 -15
- {ormlambda-4.0.0.dist-info → ormlambda-4.0.5.dist-info}/WHEEL +1 -1
- {ormlambda-4.0.0.dist-info → ormlambda-4.0.5.dist-info}/AUTHORS +0 -0
- {ormlambda-4.0.0.dist-info → ormlambda-4.0.5.dist-info}/LICENSE +0 -0
ormlambda/dialects/__init__.py
CHANGED
@@ -3,13 +3,14 @@ from typing import Callable, Optional, Type, TYPE_CHECKING, ClassVar
|
|
3
3
|
import abc
|
4
4
|
from ormlambda import util
|
5
5
|
import importlib
|
6
|
+
from ormlambda import BaseRepository
|
6
7
|
|
7
8
|
|
8
9
|
if TYPE_CHECKING:
|
10
|
+
from ormlambda import URL
|
9
11
|
from ormlambda.caster.caster import Caster
|
10
12
|
from ormlambda.repository.interfaces.IRepositoryBase import DBAPIConnection
|
11
13
|
from ormlambda.sql.types import DDLCompiler, SQLCompiler, TypeCompiler
|
12
|
-
from ormlambda import BaseRepository
|
13
14
|
|
14
15
|
|
15
16
|
class Dialect(abc.ABC):
|
@@ -57,15 +58,21 @@ class Dialect(abc.ABC):
|
|
57
58
|
type_compiler_instance: ClassVar[TypeCompiler]
|
58
59
|
"""The instance of the type compiler class used by the dialect."""
|
59
60
|
|
60
|
-
repository_cls: ClassVar[Type[BaseRepository]]
|
61
|
-
"""The repository class used by the dialect."""
|
62
|
-
|
63
61
|
caster: ClassVar[Type[Caster]]
|
64
62
|
|
65
63
|
@classmethod
|
66
64
|
def get_dialect_cls(cls) -> Type[Dialect]:
|
67
65
|
return cls
|
68
66
|
|
67
|
+
@classmethod
|
68
|
+
@abc.abstractmethod
|
69
|
+
def get_pool_class(cls, url: URL) -> Type[BaseRepository]: ...
|
70
|
+
|
71
|
+
@abc.abstractmethod
|
72
|
+
def get_dialect_pool_class(self, url: str) -> None:
|
73
|
+
"""Validates an identifier name, raising an exception if invalid"""
|
74
|
+
...
|
75
|
+
|
69
76
|
@classmethod
|
70
77
|
@abc.abstractmethod
|
71
78
|
def import_dbapi(cls) -> DBAPIConnection:
|
@@ -2,7 +2,6 @@ from ormlambda.dialects import Dialect
|
|
2
2
|
from ormlambda.sql import compiler
|
3
3
|
from typing import Optional, Any
|
4
4
|
from types import ModuleType
|
5
|
-
from ormlambda import BaseRepository
|
6
5
|
|
7
6
|
|
8
7
|
class DefaultDialect(Dialect):
|
@@ -11,7 +10,6 @@ class DefaultDialect(Dialect):
|
|
11
10
|
statement_compiler = compiler.SQLCompiler
|
12
11
|
ddl_compiler = compiler.DDLCompiler
|
13
12
|
type_compiler_cls = compiler.GenericTypeCompiler
|
14
|
-
repository_cls = BaseRepository
|
15
13
|
default_paramstyle = "named"
|
16
14
|
|
17
15
|
def __init__(
|
@@ -37,3 +35,6 @@ class DefaultDialect(Dialect):
|
|
37
35
|
self.type_compiler_instance = self.type_compiler = tt_callable(self)
|
38
36
|
|
39
37
|
super().__init__(**kwargs)
|
38
|
+
|
39
|
+
def get_dialect_pool_class(self, url):
|
40
|
+
return self.get_pool_class(url)
|
ormlambda/dialects/mysql/base.py
CHANGED
@@ -627,7 +627,6 @@ class MySQLDialect(default.DefaultDialect):
|
|
627
627
|
statement_compiler = MySQLCompiler
|
628
628
|
ddl_compiler = MySQLDDLCompiler
|
629
629
|
type_compiler_cls = MySQLTypeCompiler
|
630
|
-
repository_cls = MySQLRepository
|
631
630
|
caster = MySQLCaster
|
632
631
|
|
633
632
|
def __init__(self, **kwargs):
|
@@ -638,3 +637,7 @@ class MySQLDialect(default.DefaultDialect):
|
|
638
637
|
from mysql import connector
|
639
638
|
|
640
639
|
return connector
|
640
|
+
|
641
|
+
@classmethod
|
642
|
+
def get_pool_class(cls, url):
|
643
|
+
return MySQLRepository
|
ormlambda/engine/base.py
CHANGED
@@ -3,6 +3,7 @@ from pathlib import Path
|
|
3
3
|
from typing import TYPE_CHECKING, BinaryIO, Literal, Optional, TextIO
|
4
4
|
from ormlambda.engine import url
|
5
5
|
from ormlambda.sql.ddl import CreateSchema, DropSchema, CreateBackup
|
6
|
+
from ormlambda import BaseRepository
|
6
7
|
|
7
8
|
if TYPE_CHECKING:
|
8
9
|
from ormlambda.dialects import Dialect
|
@@ -11,10 +12,10 @@ type TypeExists = Literal["fail", "replace", "append"]
|
|
11
12
|
|
12
13
|
|
13
14
|
class Engine:
|
14
|
-
def __init__(self, dialect: Dialect, url: url.URL):
|
15
|
+
def __init__(self, repository: BaseRepository, dialect: Dialect, url: url.URL):
|
16
|
+
self.repository = repository
|
15
17
|
self.dialect = dialect
|
16
18
|
self.url = url
|
17
|
-
self.repository = self.dialect.repository_cls(url, dialect=dialect)
|
18
19
|
|
19
20
|
def __repr__(self):
|
20
21
|
return f"{Engine.__name__}: {self.url}"
|
@@ -78,3 +79,15 @@ class Engine:
|
|
78
79
|
)
|
79
80
|
.string
|
80
81
|
)
|
82
|
+
|
83
|
+
@property
|
84
|
+
def engine(self) -> Engine:
|
85
|
+
return self
|
86
|
+
|
87
|
+
@property
|
88
|
+
def driver(self) -> str:
|
89
|
+
return self.dialect.driver
|
90
|
+
|
91
|
+
@property
|
92
|
+
def name(self) -> str:
|
93
|
+
return self.dialect.name
|
ormlambda/engine/create.py
CHANGED
@@ -18,4 +18,9 @@ def create_engine(url: URL | str, **kwargs: Any) -> base.Engine:
|
|
18
18
|
dialect_args["dbapi"] = dialect_cls.import_dbapi()
|
19
19
|
|
20
20
|
dialect = dialect_cls(**dialect_args)
|
21
|
-
|
21
|
+
|
22
|
+
repositoryclass = dialect.get_dialect_pool_class(u)
|
23
|
+
|
24
|
+
repository_args = {"dialect": dialect, **kwargs}
|
25
|
+
repository = repositoryclass(u, **repository_args)
|
26
|
+
return base.Engine(repository, dialect, u)
|
ormlambda/repository/response.py
CHANGED
@@ -67,7 +67,15 @@ class Response[TFlavour, *Ts]:
|
|
67
67
|
|
68
68
|
def _tuple(**kwargs) -> list[tuple[*Ts]]:
|
69
69
|
nonlocal data
|
70
|
-
|
70
|
+
result = []
|
71
|
+
for value in data:
|
72
|
+
if len(value) ==1:
|
73
|
+
result.append(value[0])
|
74
|
+
continue
|
75
|
+
result.append(value)
|
76
|
+
|
77
|
+
|
78
|
+
return result
|
71
79
|
|
72
80
|
def _set(**kwargs) -> list[set]:
|
73
81
|
nonlocal data
|
@@ -4,7 +4,6 @@ from collections import defaultdict
|
|
4
4
|
|
5
5
|
|
6
6
|
from ormlambda import Table
|
7
|
-
from ormlambda import util
|
8
7
|
|
9
8
|
from ormlambda.common.errors import AggregateFunctionError
|
10
9
|
from ormlambda.sql.clause_info import IAggregate
|
@@ -13,6 +12,7 @@ from ormlambda.sql.clause_info import IAggregate
|
|
13
12
|
if TYPE_CHECKING:
|
14
13
|
from ormlambda.engine.base import Engine
|
15
14
|
from ormlambda.sql.clauses import Select
|
15
|
+
from ormlambda import ColumnProxy
|
16
16
|
|
17
17
|
|
18
18
|
ORDER_QUERIES = Literal["select", "join", "where", "order", "with", "group by", "limit", "offset"]
|
@@ -29,62 +29,57 @@ class ClusterResponse[T, TFlavour]:
|
|
29
29
|
self.query = query
|
30
30
|
|
31
31
|
def cluster(self, response_sql: ResponseType) -> tuple[dict[Type[Table], tuple[Table, ...]]]:
|
32
|
-
tbl_dicc: dict[Type[Table], list[dict[str, Any]]] = self._create_cluster(response_sql)
|
33
|
-
|
34
|
-
first_table = list(tbl_dicc)[0]
|
35
|
-
tuple_response = []
|
36
|
-
# it not depend of flavour attr
|
37
|
-
n_attrs = len(tbl_dicc[first_table])
|
38
|
-
for i in range(n_attrs):
|
39
|
-
new_instance = []
|
40
|
-
for table in tbl_dicc:
|
41
|
-
attrs = tbl_dicc[table][i]
|
42
|
-
new_instance.append(table(**attrs))
|
43
|
-
tuple_response.append(tuple(new_instance))
|
44
|
-
return tuple(tuple_response)
|
45
|
-
|
46
|
-
def _create_cluster(self, response_sql: ResponseType) -> dict[Type[Table], list[dict[str, Any]]]:
|
47
32
|
# We'll create a default list of dicts *once* we know how many rows are in _response_sql
|
48
|
-
row_count = len(response_sql)
|
49
33
|
|
50
|
-
|
51
|
-
|
34
|
+
tables: dict[Table, list[ColumnProxy]] = defaultdict(list)
|
35
|
+
for clause in self._select.columns:
|
36
|
+
if isinstance(clause, IAggregate):
|
37
|
+
raise AggregateFunctionError(clause)
|
52
38
|
|
53
|
-
|
39
|
+
tables[clause.table].append(clause)
|
54
40
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
41
|
+
res = []
|
42
|
+
for dicc_cols in response_sql:
|
43
|
+
converted_row = []
|
44
|
+
for table, columns in tables.items():
|
45
|
+
dicc = {}
|
46
|
+
for col in columns:
|
47
|
+
if not hasattr(col, "column_name"):
|
48
|
+
pass
|
49
|
+
dicc[col.column_name] = dicc_cols[col.alias]
|
50
|
+
converted_row.append(table(**dicc))
|
51
|
+
res.append(tuple(converted_row))
|
60
52
|
|
61
|
-
|
53
|
+
tuple_response = tuple(res)
|
62
54
|
|
63
|
-
|
64
|
-
|
65
|
-
return dict(table_attr_dict)
|
55
|
+
if not tuple_response:
|
56
|
+
return tuple_response
|
66
57
|
|
67
|
-
|
68
|
-
|
69
|
-
ColumnProxy = util.preloaded.sql_column.ColumnProxy
|
58
|
+
if len(tuple_response) == 1:
|
59
|
+
return tuple_response[0]
|
70
60
|
|
61
|
+
if len(tuple_response[0]) == 1:
|
62
|
+
return tuple([x[0] for x in tuple_response])
|
63
|
+
return tuple_response
|
64
|
+
|
65
|
+
def cluster_data(self, **kwargs) -> TFlavour[T, ...]:
|
71
66
|
if not self.flavour:
|
72
67
|
return self._return_model()
|
73
68
|
|
74
|
-
|
75
|
-
if issubclass(self.flavour, tuple) and len(self._select.used_columns()) == 1 and isinstance(self._select.used_columns()[0], ColumnProxy):
|
76
|
-
return tuple([x[0] for x in result])
|
77
|
-
return result
|
69
|
+
return self._return_flavour(self.flavour, **kwargs)
|
78
70
|
|
79
|
-
def _return_flavour[TValue](self, flavour: Type[TValue],
|
80
|
-
return self.engine.repository.read_sql(
|
71
|
+
def _return_flavour[TValue](self, flavour: Type[TValue], **kwargs) -> tuple[TValue]:
|
72
|
+
return self.engine.repository.read_sql(
|
73
|
+
query=self.query,
|
74
|
+
flavour=flavour,
|
75
|
+
select=self._select,
|
76
|
+
**kwargs,
|
77
|
+
)
|
81
78
|
|
82
79
|
def _return_model(self) -> tuple[tuple[T]]:
|
83
|
-
response_sql = self.
|
80
|
+
response_sql = self._return_flavour(flavour=dict)
|
81
|
+
|
84
82
|
if response_sql and isinstance(response_sql, Iterable):
|
85
|
-
|
86
|
-
if response and len(response[0]) == 1:
|
87
|
-
return tuple([x[0] for x in response])
|
88
|
-
return response
|
83
|
+
return self.cluster(response_sql)
|
89
84
|
|
90
85
|
return response_sql
|
@@ -214,9 +214,9 @@ class IStatements[T: Table](Element):
|
|
214
214
|
|
215
215
|
# region deal with flavours
|
216
216
|
@overload
|
217
|
-
def select[TFlavour](self, selector: Callable[[T], tuple[tuple]] = ..., *, flavour: Type[TFlavour], **kwargs) -> tuple[TFlavour, ...]: ...
|
218
|
-
@overload
|
219
217
|
def select[*TRes](self, selector: Callable[[T], tuple[*TRes]] = ..., *, flavour: Type[tuple], **kwargs) -> tuple[tuple[*TRes]]: ...
|
218
|
+
@overload
|
219
|
+
def select[TFlavour](self, selector: Callable[[T], tuple] = ..., *, flavour: Type[TFlavour], **kwargs) -> tuple[TFlavour, ...]: ...
|
220
220
|
|
221
221
|
# endregion
|
222
222
|
|
@@ -244,7 +244,7 @@ class IStatements[T: Table](Element):
|
|
244
244
|
@overload
|
245
245
|
def select_one[*TRes](self, selector: Callable[[T], tuple[*TRes]], *, flavour: Type[list], by: JoinType = ..., alias: Optional[AliasType[ColumnType]] = ..., avoid_duplicates: bool = ...) -> tuple[*TRes]: ...
|
246
246
|
@overload
|
247
|
-
def select_one[TFlavour, *TRes](self, selector: Callable[[T], tuple[
|
247
|
+
def select_one[TFlavour, *TRes](self, selector: Callable[[T], tuple[*TRes]], *, flavour: Type[TFlavour], by: JoinType = ..., alias: Optional[AliasType[ColumnType]] = ..., avoid_duplicates: bool = ...) -> TFlavour[*TRes]: ...
|
248
248
|
|
249
249
|
@abstractmethod
|
250
250
|
def select_one(
|
@@ -271,7 +271,7 @@ class IStatements[T: Table](Element):
|
|
271
271
|
@overload
|
272
272
|
def first[*TRes](self, selector: Callable[[T], tuple[*TRes]], *, flavour: Type[list], by: JoinType = ..., alias: Optional[AliasType[ColumnType]] = ..., avoid_duplicates: bool = ...) -> tuple[*TRes]: ...
|
273
273
|
@overload
|
274
|
-
def first[TFlavour, *TRes](self, selector: Callable[[T], tuple[
|
274
|
+
def first[TFlavour, *TRes](self, selector: Callable[[T], tuple[*TRes]], *, flavour: Type[TFlavour], by: JoinType = ..., alias: Optional[AliasType[ColumnType]] = ..., avoid_duplicates: bool = ...) -> TFlavour[*TRes]: ...
|
275
275
|
|
276
276
|
@abstractmethod
|
277
277
|
def first(
|
@@ -277,7 +277,7 @@ class Statements[T: Table](IStatements[T]):
|
|
277
277
|
self._query_builder.by = by
|
278
278
|
self._query: str = self._query_builder.query(self._dialect)
|
279
279
|
|
280
|
-
return ClusterResponse(select, self._engine, flavour, self._query).
|
280
|
+
return ClusterResponse(select, self._engine, flavour, self._query).cluster_data()
|
281
281
|
|
282
282
|
@override
|
283
283
|
def select_one[TValue, TFlavour, *Ts](
|
@@ -301,11 +301,8 @@ class Statements[T: Table](IStatements[T]):
|
|
301
301
|
# select columns from different tables using a join query
|
302
302
|
# FIXME [x]: before it was if len(response) == 1 and len(response[0]) == 1: return response[0][0]
|
303
303
|
if len(response) == 1:
|
304
|
-
|
305
|
-
|
306
|
-
else:
|
307
|
-
return response[0]
|
308
|
-
return tuple([res[0] for res in response])
|
304
|
+
return response[0]
|
305
|
+
return response
|
309
306
|
|
310
307
|
@override
|
311
308
|
def first[TValue, TFlavour, *Ts](
|
@@ -1,12 +1,13 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: ormlambda
|
3
|
-
Version: 4.0.
|
3
|
+
Version: 4.0.5
|
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
|
+
Classifier: Programming Language :: Python :: 3.13
|
10
11
|
Requires-Dist: mysql-connector-python (>=9.0.0,<10.0.0)
|
11
12
|
Requires-Dist: shapely (>=2.0.6,<3.0.0)
|
12
13
|
Description-Content-Type: text/markdown
|
@@ -90,16 +91,7 @@ If we were used `select_one` method, we retrieved `tuple[Address, City, Country]
|
|
90
91
|
|
91
92
|
## Filter by `where` condition
|
92
93
|
|
93
|
-
|
94
|
-
```python
|
95
|
-
result = AddressModel.where(
|
96
|
-
[
|
97
|
-
Address.address_id >= 10,
|
98
|
-
Address.address_id <= 30,
|
99
|
-
]
|
100
|
-
).select()
|
101
|
-
```
|
102
|
-
Or by using a lambda function that returns an iterable for tables where the name is unusually long.
|
94
|
+
We can use lambda function that returns an iterable to pass the iterable like.
|
103
95
|
|
104
96
|
```python
|
105
97
|
result = AddressModel.where(
|
@@ -119,7 +111,7 @@ result = AddressModel.where(Address.City.Country.country_id == 87).select()
|
|
119
111
|
We can also return `Address`, `City` or `Country` if needed.
|
120
112
|
|
121
113
|
```python
|
122
|
-
result = AddressModel.where(
|
114
|
+
result = AddressModel.where(lambda x: x.City.Country.country_id == 87).select(lambda x: (x, x.City, x.City.Country))
|
123
115
|
```
|
124
116
|
|
125
117
|
### Pass variables to the `where` method
|
@@ -127,10 +119,10 @@ result = AddressModel.where(Address.City.Country.country_id == 87).select(lambda
|
|
127
119
|
LOWER = 10
|
128
120
|
UPPER = 30
|
129
121
|
|
130
|
-
AddressModel.where(
|
122
|
+
AddressModel.where(lambda x:
|
131
123
|
[
|
132
|
-
|
133
|
-
|
124
|
+
x.address_id >= LOWER,
|
125
|
+
x.address_id <= UPPER,
|
134
126
|
]
|
135
127
|
).select()
|
136
128
|
```
|
@@ -238,7 +230,7 @@ result = (
|
|
238
230
|
AddressModel
|
239
231
|
.order(lambda a: a.address_id, order_type="DESC")
|
240
232
|
.where(lambda x: x.City.Country.country_id >= 50)
|
241
|
-
.select(
|
233
|
+
.select()
|
242
234
|
)
|
243
235
|
|
244
236
|
```
|
@@ -246,13 +238,12 @@ Also you can use `ConditionType` enum for `regular expressions` and get, for exa
|
|
246
238
|
|
247
239
|
|
248
240
|
```python
|
249
|
-
|
241
|
+
response = (
|
250
242
|
AddressModel
|
251
|
-
.order(
|
252
|
-
.where(
|
243
|
+
.order(lambda x: x.address_id, order_type="DESC")
|
244
|
+
.where(lambda x: x.City.Country.country.regex(r"^[A]"))
|
253
245
|
.limit(100)
|
254
|
-
.select(
|
255
|
-
lambda a: (
|
246
|
+
.select(lambda a: (
|
256
247
|
a,
|
257
248
|
a.City,
|
258
249
|
a.City.Country,
|
@@ -261,13 +252,9 @@ address, city, country = (
|
|
261
252
|
)
|
262
253
|
|
263
254
|
|
264
|
-
for a in
|
255
|
+
for a,c,co in response:
|
265
256
|
print(a.address_id)
|
266
|
-
|
267
|
-
for c in city:
|
268
257
|
print(c.city_id)
|
269
|
-
|
270
|
-
for co in country:
|
271
258
|
print(co.country)
|
272
259
|
```
|
273
260
|
|
@@ -276,10 +263,9 @@ In the example above, we see that the `result` var returns a tuple of tuples. Ho
|
|
276
263
|
|
277
264
|
```python
|
278
265
|
result = (
|
279
|
-
AddressModel.where(
|
266
|
+
AddressModel.where(lambda x: x.City.Country.country.regex(r"^[A]"))
|
280
267
|
.limit(100)
|
281
|
-
.select(
|
282
|
-
lambda a: (
|
268
|
+
.select(lambda a: (
|
283
269
|
a.address_id,
|
284
270
|
a.City.city_id,
|
285
271
|
a.City.Country.country_id,
|
@@ -318,28 +304,23 @@ The `concat` method allows you to concatenate multiple columns or values into a
|
|
318
304
|
### Usage
|
319
305
|
|
320
306
|
```python
|
321
|
-
response =
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
)
|
334
|
-
),
|
335
|
-
),
|
336
|
-
flavour=dict,
|
337
|
-
)
|
307
|
+
response = (
|
308
|
+
ORM(Address, db)
|
309
|
+
.where(lambda x: x.City.Country.country.regex(r"^Spain"))
|
310
|
+
.first(
|
311
|
+
lambda x: (
|
312
|
+
x.address,
|
313
|
+
x.City.city,
|
314
|
+
Concat(("Address: ", x.address, " - city: ", x.City.city, " - country: ", x.City.Country.country)),
|
315
|
+
),
|
316
|
+
flavour=dict,
|
317
|
+
)
|
318
|
+
)
|
338
319
|
|
339
320
|
{
|
340
|
-
"
|
341
|
-
"
|
342
|
-
"
|
321
|
+
"address": "939 Probolinggo Loop",
|
322
|
+
"city": "A Coruña (La Coruña)",
|
323
|
+
"concat": "Address: 939 Probolinggo Loop - city: A Coruña (La Coruña) - country: Spain",
|
343
324
|
}
|
344
325
|
```
|
345
326
|
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.
|
@@ -390,7 +371,7 @@ res = (
|
|
390
371
|
.select(lambda x:
|
391
372
|
(
|
392
373
|
x.district,
|
393
|
-
Count(x.address),
|
374
|
+
Count(x.address,alias="count"),
|
394
375
|
),
|
395
376
|
flavour=Response,
|
396
377
|
)
|
@@ -442,11 +423,10 @@ print(select.city)
|
|
442
423
|
print(select.country)
|
443
424
|
```
|
444
425
|
|
445
|
-
##
|
446
|
-
|
426
|
+
## Aggregation method
|
427
|
+
You can also use `aggregation methods` to create more informative queries.
|
447
428
|
```python
|
448
|
-
result = AddressModel.select_one(
|
449
|
-
lambda x: (
|
429
|
+
result = AddressModel.select_one(lambda x: (
|
450
430
|
Min(x.address_id),
|
451
431
|
Max(x.address_id),
|
452
432
|
Count(x.address_id),
|
@@ -17,11 +17,11 @@ ormlambda/common/interfaces/IJoinSelector.py,sha256=-w-MJmwq65tpDLtigWSLgvAqeOl7
|
|
17
17
|
ormlambda/common/interfaces/INonQueryCommand.py,sha256=7CjLW4sKqkR5zUIGvhRXOtzTs6vypJW1a9EJHlgCw2c,260
|
18
18
|
ormlambda/common/interfaces/IQueryCommand.py,sha256=PKkAI1SE6U7kcbqFgQsdTQ3asIx-gIp5RDXYlBfANJk,461
|
19
19
|
ormlambda/common/interfaces/__init__.py,sha256=-qIJf5fBX0y0vq_O7YjImWFimbj5pqONzK8udH2CMX4,169
|
20
|
-
ormlambda/dialects/__init__.py,sha256
|
20
|
+
ormlambda/dialects/__init__.py,sha256=iykTU_kv3w_FaLWZuxxcVUfvUznrM1YNWyABYlZqEXg,3736
|
21
21
|
ormlambda/dialects/default/__init__.py,sha256=N1B0LKEDu7r2-mTF9mBA4ReyhYeDuJDnbQCiH4hJvFQ,33
|
22
|
-
ormlambda/dialects/default/base.py,sha256
|
22
|
+
ormlambda/dialects/default/base.py,sha256=-cxwjUipQITbIPqWV7N0H8UlIXgxs-qeQhJlDbAHvL8,1089
|
23
23
|
ormlambda/dialects/mysql/__init__.py,sha256=DwoefrtyJUivg7z4QS4K2k0DrUu04ItC5LJcDQEYZWg,1398
|
24
|
-
ormlambda/dialects/mysql/base.py,sha256=
|
24
|
+
ormlambda/dialects/mysql/base.py,sha256=jtt1US1wILOebN7hfYmN9JzreG-_Awv9ahmzNPK0z_k,21539
|
25
25
|
ormlambda/dialects/mysql/caster/__init__.py,sha256=Df2sdZaAJ1Mi5Ego0sILMk5pF1NbK-nlV0hbpzd0PWE,47
|
26
26
|
ormlambda/dialects/mysql/caster/caster.py,sha256=G2CDqkrmsxFrHe_nDOmqqrTA_3O2o6gIIfukqPeHmJs,1021
|
27
27
|
ormlambda/dialects/mysql/caster/types/__init__.py,sha256=BmtHuVvKGPIOCjVuqQZgtGBMnx15YnGBaBi4r3Hd-3U,587
|
@@ -49,8 +49,8 @@ ormlambda/dialects/sqlite/__init__.py,sha256=2EMmxD7ORtGoD18GJ_9aC_tPutAq9ormMZJ
|
|
49
49
|
ormlambda/dialects/sqlite/base.py,sha256=24LSB461yQDEnXa-TsQt_srJmBCAR6M6419pa40CL_4,1503
|
50
50
|
ormlambda/dialects/sqlite/pysqlite.py,sha256=dZY0NV2IvSTk3DNEDyncstmIABKj3M2xfmhf2dc2zQs,680
|
51
51
|
ormlambda/engine/__init__.py,sha256=JpCLfuW1zcJi4ki97ajXh0aQxMSvWBKzDlBZx9ZVF9o,132
|
52
|
-
ormlambda/engine/base.py,sha256=
|
53
|
-
ormlambda/engine/create.py,sha256=
|
52
|
+
ormlambda/engine/base.py,sha256=BUzSRGbe-_dlh71gdHNlD1z8OyiM2K3QAV-Ul5JV_XQ,2868
|
53
|
+
ormlambda/engine/create.py,sha256=z9MDi_ldwuCa4b_Oe-orgt6Fk1EagsjKmLHZvJ0jHN8,711
|
54
54
|
ormlambda/engine/url.py,sha256=ZzdgZU_Cnjhonbbr5OfBvq_ThUPnDj9v-3-7O54ENm0,26137
|
55
55
|
ormlambda/engine/utils.py,sha256=fFoiKsiFuLcjcBVYNebVoYnMrEj3aZdoxEVSNfCY-GM,522
|
56
56
|
ormlambda/env.py,sha256=rCZKT2rpvRF3hPtkLmtiaVAIxQ0xj8tF7ZKJpFp7BkA,736
|
@@ -58,11 +58,11 @@ ormlambda/errors.py,sha256=ltLR52g3fnUTjrDC_x_R9-b5LlLjC6bVACnOoc9-OZg,839
|
|
58
58
|
ormlambda/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
59
59
|
ormlambda/model/base_model.py,sha256=lhtJWiGXiRWLOxsuPg0PPr53shhreMy69Ps2-7dYU7U,739
|
60
60
|
ormlambda/repository/__init__.py,sha256=4KAhKn6vWV7bslewvGMNqbbbUnz1DLnH4yy-M5QNAQA,112
|
61
|
-
ormlambda/repository/base_repository.py,sha256=
|
61
|
+
ormlambda/repository/base_repository.py,sha256=QGFPDg_Y12YEOEJYjkvsHErJS5-IIPxejTVwnnf_qzI,1322
|
62
62
|
ormlambda/repository/interfaces/IDatabaseConnection.py,sha256=pxczjx0b53yjjg5hvVDloMgUTFDahVC3HlJLQjo9_1w,283
|
63
63
|
ormlambda/repository/interfaces/IRepositoryBase.py,sha256=jTlViARH5SWIcYXstmXhttvNOShJ5mmAbTEmfGLiRuA,3527
|
64
64
|
ormlambda/repository/interfaces/__init__.py,sha256=t8Mn0aRZm8uF4MGaqjEANTTADCdOwNF0THZ_qebyzwo,126
|
65
|
-
ormlambda/repository/response.py,sha256=
|
65
|
+
ormlambda/repository/response.py,sha256=ZCV3joh_IMtcAHR_JIhbOudRT5ejPyXBFrHsTJoTz9o,4729
|
66
66
|
ormlambda/sql/__init__.py,sha256=C5tpRVPZFnk8h1GSUkAM83u0M-IiOWtxrQSzD5DFZYU,211
|
67
67
|
ormlambda/sql/clause_info/__init__.py,sha256=tbDXMGPjIc1e4YpBycjmyh8gRFgqZLva6sH-9awsni4,98
|
68
68
|
ormlambda/sql/clause_info/clause_info.py,sha256=OnVyjDcisJK7-exFCgk7xqyXFGMTBMxzIXEg8RF56DI,14107
|
@@ -117,11 +117,11 @@ ormlambda/sql/type_api.py,sha256=nR5NruI6kUHefcyjqmV_uxy3dM3McCWv3THg2NxXJH8,121
|
|
117
117
|
ormlambda/sql/types.py,sha256=A1HI8HrANruuAPIfl7dbbTYx3l-SvuUbPrhlzK5SZ6w,1019
|
118
118
|
ormlambda/sql/visitors.py,sha256=AHXxCEOME8-b_-YhFEzBv-Jd15vSoX5F-jEGrPPNRLE,2052
|
119
119
|
ormlambda/statements/__init__.py,sha256=9IzRSVl-ZXD4D4RrrPIifOhyO0iXSpRS5ZwvVJeAW_0,49
|
120
|
-
ormlambda/statements/base_statement.py,sha256=
|
121
|
-
ormlambda/statements/interfaces/IStatements.py,sha256=
|
120
|
+
ormlambda/statements/base_statement.py,sha256=M8h2IqMl3vQWGzjHftx0zMzp12FfOFktu1GLsj1KLpI,2741
|
121
|
+
ormlambda/statements/interfaces/IStatements.py,sha256=wTYEj8mBR21sU60ZMlHzaQehTy-knrqp3GT6n6l6HMU,9875
|
122
122
|
ormlambda/statements/interfaces/__init__.py,sha256=1EAWwBueWJ1lBG7pOAEae_Bqw6ww8s7Dnvq6LTUgUJM,51
|
123
123
|
ormlambda/statements/query_builder.py,sha256=MUTBvdlHuX6ZScyEjk4-bc6KtmpCht31NcBM1ATTyzI,10730
|
124
|
-
ormlambda/statements/statements.py,sha256=
|
124
|
+
ormlambda/statements/statements.py,sha256=U638djJtOu8qIMNlNOhJXktkFaV-cIhTsaBqy_S19h8,12091
|
125
125
|
ormlambda/statements/types.py,sha256=Qh91CB3tzrqsxsPixib7w6KLRr6zY26pHXAna6MaDm8,885
|
126
126
|
ormlambda/types/__init__.py,sha256=xVFaIMcfJvbbXs8BAvmBh8FwSiLn2R6yjZs9o-h08XM,323
|
127
127
|
ormlambda/types/metadata.py,sha256=93eJItdVDOItf7YRJUVmN_m79WLa3Ge6I414ewYnKeM,624
|
@@ -132,8 +132,8 @@ ormlambda/util/module_tree/dfs_traversal.py,sha256=lSF03G63XtJFLp03ueAmsHMBvhUkj
|
|
132
132
|
ormlambda/util/module_tree/dynamic_module.py,sha256=SQ1FZW2Es5CdACD0VS8v_UZQTuFYbUWs6diAtMbKMoA,8699
|
133
133
|
ormlambda/util/preloaded.py,sha256=1D7t25qPjhW44nRez4Sd40gLjrl6BctLhPfPsK6Dx5g,3064
|
134
134
|
ormlambda/util/typing.py,sha256=py6FbOLvnuByR8IHgKIIReFM0efX6Bzz-Ick9fx-nuw,423
|
135
|
-
ormlambda-4.0.
|
136
|
-
ormlambda-4.0.
|
137
|
-
ormlambda-4.0.
|
138
|
-
ormlambda-4.0.
|
139
|
-
ormlambda-4.0.
|
135
|
+
ormlambda-4.0.5.dist-info/AUTHORS,sha256=uWpOHaCPTOLbVkk5x9McoLwbgzSeCg7yILeDRyMGWGM,606
|
136
|
+
ormlambda-4.0.5.dist-info/LICENSE,sha256=xBprFw8GJLdHMOoUqDk0427EvjIcbEREvXXVFULuuXU,1080
|
137
|
+
ormlambda-4.0.5.dist-info/METADATA,sha256=9nElZo731sVCQr5dvymaDAIfypgU71R6PnJmJgcCOsg,12517
|
138
|
+
ormlambda-4.0.5.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
139
|
+
ormlambda-4.0.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|