ormlambda 4.0.0__py3-none-any.whl → 4.0.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.
- 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.4.dist-info}/METADATA +33 -54
- {ormlambda-4.0.0.dist-info → ormlambda-4.0.4.dist-info}/RECORD +9 -9
- {ormlambda-4.0.0.dist-info → ormlambda-4.0.4.dist-info}/AUTHORS +0 -0
- {ormlambda-4.0.0.dist-info → ormlambda-4.0.4.dist-info}/LICENSE +0 -0
- {ormlambda-4.0.0.dist-info → ormlambda-4.0.4.dist-info}/WHEEL +0 -0
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,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ormlambda
|
3
|
-
Version: 4.0.
|
3
|
+
Version: 4.0.4
|
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
|
@@ -90,16 +90,7 @@ If we were used `select_one` method, we retrieved `tuple[Address, City, Country]
|
|
90
90
|
|
91
91
|
## Filter by `where` condition
|
92
92
|
|
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.
|
93
|
+
We can use lambda function that returns an iterable to pass the iterable like.
|
103
94
|
|
104
95
|
```python
|
105
96
|
result = AddressModel.where(
|
@@ -119,7 +110,7 @@ result = AddressModel.where(Address.City.Country.country_id == 87).select()
|
|
119
110
|
We can also return `Address`, `City` or `Country` if needed.
|
120
111
|
|
121
112
|
```python
|
122
|
-
result = AddressModel.where(
|
113
|
+
result = AddressModel.where(lambda x: x.City.Country.country_id == 87).select(lambda x: (x, x.City, x.City.Country))
|
123
114
|
```
|
124
115
|
|
125
116
|
### Pass variables to the `where` method
|
@@ -127,10 +118,10 @@ result = AddressModel.where(Address.City.Country.country_id == 87).select(lambda
|
|
127
118
|
LOWER = 10
|
128
119
|
UPPER = 30
|
129
120
|
|
130
|
-
AddressModel.where(
|
121
|
+
AddressModel.where(lambda x:
|
131
122
|
[
|
132
|
-
|
133
|
-
|
123
|
+
x.address_id >= LOWER,
|
124
|
+
x.address_id <= UPPER,
|
134
125
|
]
|
135
126
|
).select()
|
136
127
|
```
|
@@ -238,7 +229,7 @@ result = (
|
|
238
229
|
AddressModel
|
239
230
|
.order(lambda a: a.address_id, order_type="DESC")
|
240
231
|
.where(lambda x: x.City.Country.country_id >= 50)
|
241
|
-
.select(
|
232
|
+
.select()
|
242
233
|
)
|
243
234
|
|
244
235
|
```
|
@@ -246,13 +237,12 @@ Also you can use `ConditionType` enum for `regular expressions` and get, for exa
|
|
246
237
|
|
247
238
|
|
248
239
|
```python
|
249
|
-
|
240
|
+
response = (
|
250
241
|
AddressModel
|
251
|
-
.order(
|
252
|
-
.where(
|
242
|
+
.order(lambda x: x.address_id, order_type="DESC")
|
243
|
+
.where(lambda x: x.City.Country.country.regex(r"^[A]"))
|
253
244
|
.limit(100)
|
254
|
-
.select(
|
255
|
-
lambda a: (
|
245
|
+
.select(lambda a: (
|
256
246
|
a,
|
257
247
|
a.City,
|
258
248
|
a.City.Country,
|
@@ -261,13 +251,9 @@ address, city, country = (
|
|
261
251
|
)
|
262
252
|
|
263
253
|
|
264
|
-
for a in
|
254
|
+
for a,c,co in response:
|
265
255
|
print(a.address_id)
|
266
|
-
|
267
|
-
for c in city:
|
268
256
|
print(c.city_id)
|
269
|
-
|
270
|
-
for co in country:
|
271
257
|
print(co.country)
|
272
258
|
```
|
273
259
|
|
@@ -276,10 +262,9 @@ In the example above, we see that the `result` var returns a tuple of tuples. Ho
|
|
276
262
|
|
277
263
|
```python
|
278
264
|
result = (
|
279
|
-
AddressModel.where(
|
265
|
+
AddressModel.where(lambda x: x.City.Country.country.regex(r"^[A]"))
|
280
266
|
.limit(100)
|
281
|
-
.select(
|
282
|
-
lambda a: (
|
267
|
+
.select(lambda a: (
|
283
268
|
a.address_id,
|
284
269
|
a.City.city_id,
|
285
270
|
a.City.Country.country_id,
|
@@ -318,28 +303,23 @@ The `concat` method allows you to concatenate multiple columns or values into a
|
|
318
303
|
### Usage
|
319
304
|
|
320
305
|
```python
|
321
|
-
response =
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
)
|
334
|
-
),
|
335
|
-
),
|
336
|
-
flavour=dict,
|
337
|
-
)
|
306
|
+
response = (
|
307
|
+
ORM(Address, db)
|
308
|
+
.where(lambda x: x.City.Country.country.regex(r"^Spain"))
|
309
|
+
.first(
|
310
|
+
lambda x: (
|
311
|
+
x.address,
|
312
|
+
x.City.city,
|
313
|
+
Concat(("Address: ", x.address, " - city: ", x.City.city, " - country: ", x.City.Country.country)),
|
314
|
+
),
|
315
|
+
flavour=dict,
|
316
|
+
)
|
317
|
+
)
|
338
318
|
|
339
319
|
{
|
340
|
-
"
|
341
|
-
"
|
342
|
-
"
|
320
|
+
"address": "939 Probolinggo Loop",
|
321
|
+
"city": "A Coruña (La Coruña)",
|
322
|
+
"concat": "Address: 939 Probolinggo Loop - city: A Coruña (La Coruña) - country: Spain",
|
343
323
|
}
|
344
324
|
```
|
345
325
|
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 +370,7 @@ res = (
|
|
390
370
|
.select(lambda x:
|
391
371
|
(
|
392
372
|
x.district,
|
393
|
-
Count(x.address),
|
373
|
+
Count(x.address,alias="count"),
|
394
374
|
),
|
395
375
|
flavour=Response,
|
396
376
|
)
|
@@ -442,11 +422,10 @@ print(select.city)
|
|
442
422
|
print(select.country)
|
443
423
|
```
|
444
424
|
|
445
|
-
##
|
446
|
-
|
425
|
+
## Aggregation method
|
426
|
+
You can also use `aggregation methods` to create more informative queries.
|
447
427
|
```python
|
448
|
-
result = AddressModel.select_one(
|
449
|
-
lambda x: (
|
428
|
+
result = AddressModel.select_one(lambda x: (
|
450
429
|
Min(x.address_id),
|
451
430
|
Max(x.address_id),
|
452
431
|
Count(x.address_id),
|
@@ -62,7 +62,7 @@ ormlambda/repository/base_repository.py,sha256=SW7VsbNddIY8-ALIGYcLlj4tFAoPSepeQ
|
|
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.4.dist-info/AUTHORS,sha256=uWpOHaCPTOLbVkk5x9McoLwbgzSeCg7yILeDRyMGWGM,606
|
136
|
+
ormlambda-4.0.4.dist-info/LICENSE,sha256=xBprFw8GJLdHMOoUqDk0427EvjIcbEREvXXVFULuuXU,1080
|
137
|
+
ormlambda-4.0.4.dist-info/METADATA,sha256=q-8Wzvr-9NpPcQKKsrh4-QBaxSIHDtpygG8bgmcZhxo,12466
|
138
|
+
ormlambda-4.0.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
139
|
+
ormlambda-4.0.4.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|