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.
@@ -67,7 +67,15 @@ class Response[TFlavour, *Ts]:
67
67
 
68
68
  def _tuple(**kwargs) -> list[tuple[*Ts]]:
69
69
  nonlocal data
70
- return data
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
- def make_list_of_dicts() -> list[dict[str, Any]]:
51
- return [{} for _ in range(row_count)]
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
- table_attr_dict = defaultdict(make_list_of_dicts)
39
+ tables[clause.table].append(clause)
54
40
 
55
- for i, dicc_cols in enumerate(response_sql):
56
- for clause in self._select.columns:
57
- # if col is None or not hasattr(table, col):
58
- if isinstance(clause, IAggregate):
59
- raise AggregateFunctionError(clause)
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
- table = clause.table
53
+ tuple_response = tuple(res)
62
54
 
63
- table_attr_dict[table][i][clause.column_name] = dicc_cols[clause.alias]
64
- # Convert back to a normal dict if you like (defaultdict is a dict subclass).
65
- return dict(table_attr_dict)
55
+ if not tuple_response:
56
+ return tuple_response
66
57
 
67
- @util.preload_module("ormlambda.sql.column")
68
- def response(self, **kwargs) -> TFlavour[T, ...]:
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
- result = self._return_flavour(self.flavour, self._select, **kwargs)
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], select, **kwargs) -> tuple[TValue]:
80
- return self.engine.repository.read_sql(self.query, flavour=flavour, select=select, **kwargs)
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.engine.repository.read_sql(self.query, flavour=dict, select=self._select) # store all columns of the SQL query
80
+ response_sql = self._return_flavour(flavour=dict)
81
+
84
82
  if response_sql and isinstance(response_sql, Iterable):
85
- response = self.cluster(response_sql)
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[T, *TRes]], *, flavour: Type[TFlavour], by: JoinType = ..., alias: Optional[AliasType[ColumnType]] = ..., avoid_duplicates: bool = ...) -> TFlavour[*TRes]: ...
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[T, *TRes]], *, flavour: Type[TFlavour], by: JoinType = ..., alias: Optional[AliasType[ColumnType]] = ..., avoid_duplicates: bool = ...) -> TFlavour[*TRes]: ...
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).response()
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
- if isinstance(response[0], Iterable) and len(response[0]) == 1:
305
- return response[0][0]
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.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
- we can use only the Original Table to pass the variables like
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(Address.City.Country.country_id == 87).select(lambda x: (x, x.City, x.City.Country))
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
- Address.address_id >= LOWER,
133
- Address.address_id <= UPPER,
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(Address)
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
- address, city, country = (
240
+ response = (
250
241
  AddressModel
251
- .order(Address.address_id, order_type="DESC")
252
- .where(Address.City.Country.country.regex(r"^[A]"))
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 address:
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(Address.City.Country.country.regex(r"^[A]"))
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 = ORM(Address, db).where(Address.City.Country.country.regex(r"^Spain")).first(
322
- (
323
- Address.address,
324
- Address.City.city,
325
- Concat(lambda x:
326
- (
327
- "Address: ",
328
- x.address,
329
- " - city: ",
330
- x.City.city,
331
- " - country: ",
332
- x.City.Country.country,
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
- "address_address": "939 Probolinggo Loop",
341
- "city_city": "A Coruña (La Coruña)",
342
- "CONCAT": "Address: 939 Probolinggo Loop - city: A Coruña (La Coruña) - country: Spain",
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
- ## Combine aggregation method
446
- 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.
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=z1e0DlToPZqMCxS3Y36P0lTBOWzhMMkla6k8IiCvYQo,4525
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=tzDRfDJrzHCvgHWxHRhePrLi4GkOq651JBow8y-5NME,3575
121
- ormlambda/statements/interfaces/IStatements.py,sha256=ZAMvQA-TtGf9ghhcHVaLcKHeJtodPyTzLPsFw8dngO4,9888
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=YXY-1nKONugKWWW3dPVjPJzFeTUcWFt0-hJpke7Oiw4,12250
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.0.dist-info/AUTHORS,sha256=uWpOHaCPTOLbVkk5x9McoLwbgzSeCg7yILeDRyMGWGM,606
136
- ormlambda-4.0.0.dist-info/LICENSE,sha256=xBprFw8GJLdHMOoUqDk0427EvjIcbEREvXXVFULuuXU,1080
137
- ormlambda-4.0.0.dist-info/METADATA,sha256=Ts-rXOPpIPNWaXEpxVAIZobEw4CnmRUuV95AIJwm50A,13140
138
- ormlambda-4.0.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
139
- ormlambda-4.0.0.dist-info/RECORD,,
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,,