ormlambda 3.35.2__py3-none-any.whl → 4.0.0__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.
Files changed (130) hide show
  1. ormlambda/__init__.py +79 -51
  2. ormlambda/caster/caster.py +6 -1
  3. ormlambda/common/abstract_classes/__init__.py +0 -2
  4. ormlambda/common/enums/__init__.py +1 -0
  5. ormlambda/common/enums/order_type.py +9 -0
  6. ormlambda/common/errors/__init__.py +13 -3
  7. ormlambda/common/global_checker.py +86 -8
  8. ormlambda/common/interfaces/IQueryCommand.py +2 -2
  9. ormlambda/common/interfaces/__init__.py +0 -2
  10. ormlambda/dialects/__init__.py +75 -3
  11. ormlambda/dialects/default/base.py +1 -1
  12. ormlambda/dialects/mysql/__init__.py +35 -78
  13. ormlambda/dialects/mysql/base.py +226 -40
  14. ormlambda/dialects/mysql/clauses/ST_AsText.py +26 -0
  15. ormlambda/dialects/mysql/clauses/ST_Contains.py +30 -0
  16. ormlambda/dialects/mysql/clauses/__init__.py +1 -0
  17. ormlambda/dialects/mysql/repository/__init__.py +1 -0
  18. ormlambda/{databases/my_sql → dialects/mysql/repository}/repository.py +0 -5
  19. ormlambda/dialects/mysql/types.py +6 -0
  20. ormlambda/engine/base.py +26 -4
  21. ormlambda/errors.py +9 -0
  22. ormlambda/model/base_model.py +3 -10
  23. ormlambda/repository/base_repository.py +1 -1
  24. ormlambda/repository/interfaces/IRepositoryBase.py +0 -7
  25. ormlambda/repository/response.py +12 -7
  26. ormlambda/sql/__init__.py +12 -3
  27. ormlambda/sql/clause_info/__init__.py +0 -2
  28. ormlambda/sql/clause_info/clause_info.py +94 -76
  29. ormlambda/sql/clause_info/interface/IAggregate.py +14 -4
  30. ormlambda/sql/clause_info/interface/IClauseInfo.py +6 -11
  31. ormlambda/sql/clauses/alias.py +6 -37
  32. ormlambda/sql/clauses/count.py +21 -36
  33. ormlambda/sql/clauses/group_by.py +13 -19
  34. ormlambda/sql/clauses/having.py +2 -6
  35. ormlambda/sql/clauses/insert.py +3 -3
  36. ormlambda/sql/clauses/interfaces/__init__.py +0 -1
  37. ormlambda/sql/clauses/join/join_context.py +5 -12
  38. ormlambda/sql/clauses/joins.py +34 -52
  39. ormlambda/sql/clauses/limit.py +1 -2
  40. ormlambda/sql/clauses/offset.py +1 -2
  41. ormlambda/sql/clauses/order.py +17 -21
  42. ormlambda/sql/clauses/select.py +56 -28
  43. ormlambda/sql/clauses/update.py +13 -10
  44. ormlambda/sql/clauses/where.py +20 -39
  45. ormlambda/sql/column/__init__.py +1 -0
  46. ormlambda/sql/column/column.py +19 -12
  47. ormlambda/sql/column/column_proxy.py +117 -0
  48. ormlambda/sql/column_table_proxy.py +23 -0
  49. ormlambda/sql/comparer.py +31 -65
  50. ormlambda/sql/compiler.py +248 -58
  51. ormlambda/sql/context/__init__.py +304 -0
  52. ormlambda/sql/ddl.py +19 -5
  53. ormlambda/sql/elements.py +3 -0
  54. ormlambda/sql/foreign_key.py +42 -64
  55. ormlambda/sql/functions/__init__.py +0 -1
  56. ormlambda/sql/functions/concat.py +35 -38
  57. ormlambda/sql/functions/max.py +12 -36
  58. ormlambda/sql/functions/min.py +13 -28
  59. ormlambda/sql/functions/sum.py +17 -33
  60. ormlambda/sql/sqltypes.py +2 -0
  61. ormlambda/sql/table/__init__.py +1 -0
  62. ormlambda/sql/table/table.py +32 -49
  63. ormlambda/sql/table/table_proxy.py +88 -0
  64. ormlambda/sql/type_api.py +4 -1
  65. ormlambda/sql/types.py +15 -12
  66. ormlambda/statements/__init__.py +0 -2
  67. ormlambda/statements/base_statement.py +51 -84
  68. ormlambda/statements/interfaces/IStatements.py +77 -123
  69. ormlambda/statements/interfaces/__init__.py +1 -1
  70. ormlambda/statements/query_builder.py +296 -128
  71. ormlambda/statements/statements.py +120 -110
  72. ormlambda/statements/types.py +5 -25
  73. ormlambda/util/__init__.py +7 -86
  74. ormlambda/util/langhelpers.py +102 -0
  75. ormlambda/util/module_tree/dynamic_module.py +1 -1
  76. ormlambda/util/preloaded.py +80 -0
  77. ormlambda/util/typing.py +12 -3
  78. {ormlambda-3.35.2.dist-info → ormlambda-4.0.0.dist-info}/METADATA +29 -31
  79. ormlambda-4.0.0.dist-info/RECORD +139 -0
  80. ormlambda/common/abstract_classes/clause_info_converter.py +0 -65
  81. ormlambda/common/abstract_classes/decomposition_query.py +0 -141
  82. ormlambda/common/abstract_classes/query_base.py +0 -15
  83. ormlambda/common/interfaces/ICustomAlias.py +0 -7
  84. ormlambda/common/interfaces/IDecompositionQuery.py +0 -33
  85. ormlambda/databases/__init__.py +0 -4
  86. ormlambda/databases/my_sql/__init__.py +0 -3
  87. ormlambda/databases/my_sql/clauses/ST_AsText.py +0 -37
  88. ormlambda/databases/my_sql/clauses/ST_Contains.py +0 -36
  89. ormlambda/databases/my_sql/clauses/__init__.py +0 -14
  90. ormlambda/databases/my_sql/clauses/count.py +0 -33
  91. ormlambda/databases/my_sql/clauses/delete.py +0 -9
  92. ormlambda/databases/my_sql/clauses/drop_table.py +0 -26
  93. ormlambda/databases/my_sql/clauses/group_by.py +0 -17
  94. ormlambda/databases/my_sql/clauses/having.py +0 -12
  95. ormlambda/databases/my_sql/clauses/insert.py +0 -9
  96. ormlambda/databases/my_sql/clauses/joins.py +0 -14
  97. ormlambda/databases/my_sql/clauses/limit.py +0 -6
  98. ormlambda/databases/my_sql/clauses/offset.py +0 -6
  99. ormlambda/databases/my_sql/clauses/order.py +0 -8
  100. ormlambda/databases/my_sql/clauses/update.py +0 -8
  101. ormlambda/databases/my_sql/clauses/upsert.py +0 -9
  102. ormlambda/databases/my_sql/clauses/where.py +0 -7
  103. ormlambda/dialects/interface/__init__.py +0 -1
  104. ormlambda/dialects/interface/dialect.py +0 -78
  105. ormlambda/sql/clause_info/aggregate_function_base.py +0 -96
  106. ormlambda/sql/clause_info/clause_info_context.py +0 -87
  107. ormlambda/sql/clauses/interfaces/ISelect.py +0 -17
  108. ormlambda/sql/clauses/new_join.py +0 -119
  109. ormlambda/util/load_module.py +0 -21
  110. ormlambda/util/plugin_loader.py +0 -32
  111. ormlambda-3.35.2.dist-info/RECORD +0 -159
  112. /ormlambda/{databases/my_sql → dialects/mysql}/caster/__init__.py +0 -0
  113. /ormlambda/{databases/my_sql → dialects/mysql}/caster/caster.py +0 -0
  114. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/__init__.py +0 -0
  115. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/boolean.py +0 -0
  116. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/bytes.py +0 -0
  117. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/date.py +0 -0
  118. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/datetime.py +0 -0
  119. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/decimal.py +0 -0
  120. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/float.py +0 -0
  121. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/int.py +0 -0
  122. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/iterable.py +0 -0
  123. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/json.py +0 -0
  124. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/none.py +0 -0
  125. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/point.py +0 -0
  126. /ormlambda/{databases/my_sql → dialects/mysql}/caster/types/string.py +0 -0
  127. /ormlambda/{databases/my_sql → dialects/mysql/repository}/pool_types.py +0 -0
  128. {ormlambda-3.35.2.dist-info → ormlambda-4.0.0.dist-info}/AUTHORS +0 -0
  129. {ormlambda-3.35.2.dist-info → ormlambda-4.0.0.dist-info}/LICENSE +0 -0
  130. {ormlambda-3.35.2.dist-info → ormlambda-4.0.0.dist-info}/WHEEL +0 -0
@@ -1,8 +1,7 @@
1
1
  from __future__ import annotations
2
2
  from typing import Concatenate, Iterable, override, Type, TYPE_CHECKING, Any, Callable, Optional
3
3
 
4
- from ormlambda import ForeignKey
5
-
4
+ from ormlambda.sql.types import ASTERISK
6
5
 
7
6
  if TYPE_CHECKING:
8
7
  from ormlambda.engine.base import Engine
@@ -11,16 +10,14 @@ if TYPE_CHECKING:
11
10
  from ormlambda.statements.types import OrderTypes
12
11
  from ormlambda.sql.types import ColumnType
13
12
  from ormlambda.statements.types import SelectCols
14
- from ormlambda.statements.interfaces import IStatements_two_generic
15
13
  from ormlambda.statements.types import TypeExists
16
- from ormlambda.sql.clause_info import IAggregate
17
14
  from ormlambda.statements.types import WhereTypes
15
+ from ormlambda.dialects import Dialect
18
16
 
17
+ from ormlambda.statements.interfaces import IStatements
18
+ from ormlambda.statements.base_statement import ClusterResponse
19
19
 
20
- from ormlambda.sql.clause_info import ClauseInfo
21
- from ormlambda.statements import BaseStatement
22
-
23
- from ormlambda import Table, Column
20
+ from ormlambda import OrderType, Table
24
21
  from ormlambda.common.enums import JoinType
25
22
  from ormlambda.sql.clauses.join import JoinContext, TupleJoinType
26
23
 
@@ -40,23 +37,53 @@ def clear_list[T, **P](f: Callable[Concatenate[Statements, P], T]) -> Callable[P
40
37
  except Exception as err:
41
38
  raise err
42
39
  finally:
43
- ForeignKey.stored_calls.clear()
44
40
  self._query_builder.clear()
45
41
 
46
42
  return wrapper
47
43
 
48
44
 
49
- class Statements[T: Table, TRepo](BaseStatement[T, None]):
45
+ class Statements[T: Table](IStatements[T]):
50
46
  def __init__(self, model: T, engine: Engine) -> None:
51
- super().__init__(model, engine)
52
- self._query_builder = QueryBuilder(self.dialect)
47
+ self._query_builder = QueryBuilder()
48
+ self._engine = engine
49
+ self._dialect = engine.dialect
50
+ self._query: Optional[str] = None
51
+ self._model: T = model[0] if isinstance(model, Iterable) else model
52
+
53
+ if not issubclass(self._model, Table):
54
+ # Deben heredar de Table ya que es la forma que tenemos para identificar si estamos pasando una instancia del tipo que corresponde o no cuando llamamos a insert o upsert.
55
+ # Si no heredase de Table no sabriamos identificar el tipo de dato del que se trata porque al llamar a isinstance, obtendriamos el nombre de la clase que mapea a la tabla, Encargo, Edificio, Presupuesto y no podriamos crear una clase generica
56
+ raise Exception(f"'{model}' class does not inherit from Table class")
57
+
58
+ @property
59
+ def dialect(self) -> Dialect:
60
+ return self._dialect
61
+
62
+ @property
63
+ def engine(self) -> Engine:
64
+ return self._engine
65
+
66
+ @override
67
+ def table_exists(self) -> bool:
68
+ return self.engine.repository.table_exists(self._model.__table_name__)
69
+
70
+ def __repr__(self):
71
+ return f"<Model: {self.__class__.__name__}>"
72
+
73
+ @property
74
+ def query(self) -> str:
75
+ return self._query
76
+
77
+ @property
78
+ def model(self) -> Type[T]:
79
+ return self._model
53
80
 
54
81
  @override
55
82
  def create_table(self, if_exists: TypeExists = "fail") -> None:
56
83
  name: str = self._model.__table_name__
57
- if self._repository.table_exists(name):
84
+ if self.engine.repository.table_exists(name):
58
85
  if if_exists == "replace":
59
- self._repository.drop_table(name)
86
+ self.drop_table()
60
87
 
61
88
  elif if_exists == "fail":
62
89
  raise ValueError(f"Table '{self._model.__table_name__}' already exists")
@@ -64,7 +91,7 @@ class Statements[T: Table, TRepo](BaseStatement[T, None]):
64
91
  elif if_exists == "append":
65
92
  counter: int = 0
66
93
  char: str = ""
67
- while self._repository.table_exists(name + char):
94
+ while self.engine.repository.table_exists(name + char):
68
95
  counter += 1
69
96
  char = f"_{counter}"
70
97
  name += char
@@ -74,18 +101,25 @@ class Statements[T: Table, TRepo](BaseStatement[T, None]):
74
101
  return new_model.create_table(self.dialect)
75
102
 
76
103
  query = self.model.create_table(self.dialect)
77
- self._repository.execute(query)
104
+ self.engine.repository.execute(query)
105
+ return None
106
+
107
+ @override
108
+ def drop_table(self) -> None:
109
+ q = self.model.drop_table(self.dialect)
110
+ self.engine.repository.execute(q)
78
111
  return None
79
112
 
80
113
  @override
81
114
  @clear_list
82
115
  def insert(self, instances: T | list[T]) -> None:
83
- insert = clauses.Insert(self._model, self.repository, self._dialect)
116
+ insert = clauses.Insert(self._model, self.engine.repository, self._dialect)
84
117
  insert.insert(instances)
85
118
  insert.execute()
86
119
  return None
87
120
 
88
121
  @override
122
+ @clear_list
89
123
  def delete(self, instances: Optional[T | list[T]] = None) -> None:
90
124
  if instances is None:
91
125
  response = self.select()
@@ -95,7 +129,7 @@ class Statements[T: Table, TRepo](BaseStatement[T, None]):
95
129
  # We always going to have a tuple of one element
96
130
  return self.delete(response)
97
131
 
98
- delete = clauses.Delete(self._model, self._repository, engine=self._engine)
132
+ delete = clauses.Delete(self._model, self.engine.repository, engine=self._engine)
99
133
  delete.delete(instances)
100
134
  delete.execute()
101
135
  # not necessary to call self._query_builder.clear() because select() method already call it
@@ -104,7 +138,7 @@ class Statements[T: Table, TRepo](BaseStatement[T, None]):
104
138
  @override
105
139
  @clear_list
106
140
  def upsert(self, instances: T | list[T]) -> None:
107
- upsert = clauses.Upsert(self._model, self._repository, engine=self._engine)
141
+ upsert = clauses.Upsert(self._model, self.engine.repository, engine=self._engine)
108
142
  upsert.upsert(instances)
109
143
  upsert.execute()
110
144
  return None
@@ -112,107 +146,96 @@ class Statements[T: Table, TRepo](BaseStatement[T, None]):
112
146
  @override
113
147
  @clear_list
114
148
  def update(self, dicc: dict[str, Any] | list[dict[str, Any]]) -> None:
115
- update = clauses.Update(self._model, self._repository, self._query_builder.WHERE, engine=self._engine)
149
+ update = clauses.Update(self._model, self.engine.repository, self._query_builder.components.where, engine=self._engine)
116
150
  update.update(dicc)
117
151
  update.execute()
118
152
 
119
153
  return None
120
154
 
121
155
  @override
122
- def limit(self, number: int) -> IStatements_two_generic[T, TRepo]:
123
- limit = clauses.Limit(number, dialect=self._dialect)
156
+ def limit(self, number: int) -> IStatements[T]:
124
157
  # Only can be one LIMIT SQL parameter. We only use the last LimitQuery
158
+ limit = clauses.Limit(number=number)
125
159
  self._query_builder.add_statement(limit)
126
160
  return self
127
161
 
128
162
  @override
129
- def offset(self, number: int) -> IStatements_two_generic[T, TRepo]:
130
- offset = clauses.Offset(number, dialect=self._dialect)
163
+ def offset(self, number: int) -> IStatements[T]:
164
+ offset = clauses.Offset(number=number)
131
165
  self._query_builder.add_statement(offset)
132
166
  return self
133
167
 
134
168
  @override
135
169
  def count[TProp](
136
170
  self,
137
- selection: None | SelectCols[T, TProp] = lambda x: "*",
138
- alias="count",
139
- execute: bool = False,
171
+ selection: Optional[SelectCols[T, TProp] | str] = ASTERISK,
172
+ alias: AliasType = "count",
140
173
  ) -> Optional[int]:
141
- if execute is True:
142
- return self.select_one(self.count(selection, alias, False), flavour=dict)[alias]
143
-
144
- selection = GlobalChecker.resolved_callback_object(selection, self.models)
145
- return clauses.Count(
146
- element=selection,
147
- alias_clause=alias,
148
- context=self._query_builder._context,
149
- dialect=self._dialect,
150
- )
174
+ if selection == ASTERISK:
175
+ return self.select_one(lambda x: clauses.Count(x, alias), flavour=dict)[alias]
176
+
177
+ # get first position because 'resolved_callback_object' return an, alway Iterable and we should only pass one column
178
+ res = GlobalChecker.resolved_callback_object(self.model, selection)[0]
179
+ return self.select_one(lambda x: clauses.Count(res, alias), flavour=dict)[alias]
151
180
 
152
181
  @override
153
- def where(self, conditions: WhereTypes) -> IStatements_two_generic[T, TRepo]:
182
+ def where(self, conditions: WhereTypes[T], restrictive: bool = True) -> IStatements[T]:
154
183
  # FIXME [x]: I've wrapped self._model into tuple to pass it instance attr. Idk if it's correct
184
+ result = GlobalChecker.resolved_callback_object(self.model, conditions)
155
185
 
156
- conditions = GlobalChecker.resolved_callback_object(conditions, self._models)
157
- if not isinstance(conditions, Iterable):
158
- conditions = (conditions,)
159
- self._query_builder.add_statement(clauses.Where(*conditions))
186
+ where = clauses.Where(*result, restrictive=restrictive)
187
+ self._query_builder.add_statement(where)
160
188
  return self
161
189
 
162
190
  @override
163
- def having(self, conditions: WhereTypes) -> IStatements_two_generic[T, TRepo]:
164
- conditions = GlobalChecker.resolved_callback_object(conditions, self._models)
165
- if not isinstance(conditions, Iterable):
166
- conditions = (conditions,)
167
- self._query_builder.add_statement(clauses.Having(*conditions))
191
+ def having(self, conditions: ColumnType, restrictive: bool = True) -> IStatements[T]:
192
+ result = GlobalChecker.resolved_callback_object(self.model, conditions)
193
+ having = clauses.Having(*result, restrictive=restrictive)
194
+ self._query_builder.add_statement(having)
168
195
  return self
169
196
 
170
197
  @override
171
- def order[TValue](self, columns: Callable[[T], TValue], order_type: OrderTypes) -> IStatements_two_generic[T, TRepo]:
172
- query = GlobalChecker.resolved_callback_object(columns, self._models)
173
- order = clauses.Order(query, order_type, dialect=self._dialect)
174
- self._query_builder.add_statement(order)
175
- return self
198
+ def order[TValue](self, columns: str | Callable[[T], TValue], order_type: OrderTypes = OrderType.ASC) -> IStatements[T]:
199
+ if isinstance(columns, str):
200
+ callable_func = lambda x: columns # noqa: E731
201
+ else:
202
+ callable_func = columns
176
203
 
177
- @override
178
- def concat(self, selector: SelectCols[T, str], alias: str = "concat") -> IAggregate:
179
- return func.Concat(values=selector, alias_clause=alias, context=self._query_builder._context, dialect=self._dialect)
204
+ res = GlobalChecker.resolved_callback_object(self.model, callable_func)
205
+ deferred_op = clauses.Order(*res, order_type=order_type)
206
+ self._query_builder.add_statement(deferred_op)
207
+
208
+ return self
180
209
 
181
210
  @override
182
211
  def max[TProp](
183
212
  self,
184
213
  column: SelectCols[T, TProp],
185
- alias: str = "max",
186
- execute: bool = False,
214
+ alias: AliasType = "max",
187
215
  ) -> int:
188
- column = GlobalChecker.resolved_callback_object(column, self.models)
189
- if execute is True:
190
- return self.select_one(self.max(column, alias, execute=False), flavour=dict)[alias]
191
- return func.Max(elements=column, alias_clause=alias, context=self._query_builder._context, dialect=self._dialect)
216
+ res = GlobalChecker.resolved_callback_object(self.model, column)[0]
217
+
218
+ return self.select_one(lambda x: func.Max(res, alias), flavour=dict)[alias]
192
219
 
193
220
  @override
194
221
  def min[TProp](
195
222
  self,
196
223
  column: SelectCols[T, TProp],
197
- alias: str = "min",
198
- execute: bool = False,
224
+ alias: AliasType = "min",
199
225
  ) -> int:
200
- column = GlobalChecker.resolved_callback_object(column, self.models)
201
- if execute is True:
202
- return self.select_one(self.min(column, alias, execute=False), flavour=dict)[alias]
203
- return func.Min(elements=column, alias_clause=alias, context=self._query_builder._context, dialect=self._dialect)
226
+ res = GlobalChecker.resolved_callback_object(self.model, column)[0]
227
+
228
+ return self.select_one(lambda x: func.Min(res, alias), flavour=dict)[alias]
204
229
 
205
230
  @override
206
231
  def sum[TProp](
207
232
  self,
208
233
  column: SelectCols[T, TProp],
209
- alias: str = "sum",
210
- execute: bool = False,
234
+ alias: AliasType = "sum",
211
235
  ) -> int:
212
- column = GlobalChecker.resolved_callback_object(column, self.models)
213
- if execute is True:
214
- return self.select_one(self.sum(column, alias, execute=False), flavour=dict)[alias]
215
- return func.Sum(elements=column, alias_clause=alias, context=self._query_builder._context, dialect=self._dialect)
236
+ res = GlobalChecker.resolved_callback_object(self.model, column)[0]
237
+
238
+ return self.select_one(lambda x: func.Sum(res, alias), flavour=dict)[alias]
216
239
 
217
240
  @override
218
241
  def join[LTable: Table, LProp, RTable: Table, RProp](self, joins: tuple[TupleJoinType[LTable, LProp, RTable, RProp]]) -> JoinContext[tuple[*TupleJoinType[LTable, LProp, RTable, RProp]]]:
@@ -226,39 +249,35 @@ class Statements[T: Table, TRepo](BaseStatement[T, None]):
226
249
  *,
227
250
  flavour: Optional[Type[TFlavour]] = None,
228
251
  by: JoinType = JoinType.INNER_JOIN,
252
+ alias: Optional[AliasType[T]] = None,
253
+ avoid_duplicates: bool = False,
229
254
  **kwargs,
230
255
  ):
231
- if "alias" in kwargs:
232
- alias = kwargs.pop("alias")
233
- kwargs["alias_clause"] = alias
234
- select_clause = GlobalChecker.resolved_callback_object(selector, self._models)
235
-
236
256
  if selector is None:
237
257
  # COMMENT: if we do not specify any lambda function we assumed the user want to retreive only elements of the Model itself avoiding other models
238
- result = self.select(selector=lambda x: x, flavour=flavour, by=by)
239
- # COMMENT: Always we want to retrieve tuple[tuple[Any]]. That's the reason to return result[0] when we ensure the user want only objects of the first table.
240
- # Otherwise, we wil return the result itself
241
- if flavour:
242
- return result
243
- return () if not result else result[0]
258
+ result = self.select(
259
+ selector=lambda x: x,
260
+ flavour=flavour,
261
+ by=by,
262
+ avoid_duplicates=avoid_duplicates,
263
+ **kwargs,
264
+ )
265
+ return result
266
+ select_clause = GlobalChecker.resolved_callback_object(self.model, selector)
244
267
 
245
268
  select = clauses.Select(
246
- self._models,
269
+ table=self.model,
247
270
  columns=select_clause,
248
- dialect=self.dialect,
249
- **kwargs,
271
+ alias=alias,
272
+ avoid_duplicates=avoid_duplicates,
250
273
  )
274
+
251
275
  self._query_builder.add_statement(select)
252
276
 
253
277
  self._query_builder.by = by
254
278
  self._query: str = self._query_builder.query(self._dialect)
255
279
 
256
- if flavour:
257
- result = self._return_flavour(self.query, flavour, select, **kwargs)
258
- if issubclass(flavour, tuple) and isinstance(select_clause, Column | ClauseInfo):
259
- return tuple([x[0] for x in result])
260
- return result
261
- return self._return_model(select, self.query)
280
+ return ClusterResponse(select, self._engine, flavour, self._query).response()
262
281
 
263
282
  @override
264
283
  def select_one[TValue, TFlavour, *Ts](
@@ -305,22 +324,13 @@ class Statements[T: Table, TRepo](BaseStatement[T, None]):
305
324
  )
306
325
 
307
326
  @override
308
- def groupby[TProp](self, column: ColumnType[TProp] | Callable[[T], Any]) -> IStatements_two_generic[T]:
309
- column = GlobalChecker.resolved_callback_object(column, self.models)
310
-
311
- groupby = clauses.GroupBy(column=column, context=self._query_builder._context, dialect=self.dialect)
312
- # Only can be one LIMIT SQL parameter. We only use the last LimitQuery
313
- self._query_builder.add_statement(groupby)
327
+ def groupby[TProp](self, column: ColumnType[TProp] | Callable[[T], Any]) -> IStatements[T]:
328
+ result = GlobalChecker.resolved_callback_object(self.model, column)
329
+ deferred_op = clauses.GroupBy(*result)
330
+ self._query_builder.add_statement(deferred_op)
314
331
  return self
315
332
 
316
- @override
317
- def alias[TProp](self, column: SelectCols[T, TProp], alias: AliasType[ClauseInfo[T]]) -> clauses.Alias[T]:
318
- column = GlobalChecker.resolved_callback_object(column, self.models)
319
-
320
- return clauses.Alias(
321
- table=column.table,
322
- column=column,
323
- alias_clause=alias,
324
- context=self._query_builder._context,
325
- dialect=self.dialect,
326
- )
333
+ def compile(self) -> str:
334
+ if not self._query:
335
+ return self._query_builder.query(self._dialect)
336
+ return self._query
@@ -7,50 +7,30 @@ from typing import (
7
7
  Union,
8
8
  TYPE_CHECKING,
9
9
  )
10
- import enum
11
10
 
12
11
 
13
12
  if TYPE_CHECKING:
14
13
  from ormlambda.common.enums import JoinType
15
14
  from ormlambda.sql.comparer import Comparer
16
15
  from ormlambda.sql.types import ColumnType
16
+ from ormlambda.common.enums import OrderType
17
17
 
18
18
  type OrderTypes = Literal["ASC", "DESC"] | OrderType | Iterable[OrderType]
19
19
 
20
20
 
21
- class OrderType(str, enum.Enum):
22
- def __str__(self):
23
- return super().__str__()
24
-
25
- ASC = "ASC"
26
- DESC = "DESC"
27
-
28
-
29
- type Tuple[T] = tuple[T, ...]
30
-
31
- type Select2[T1, T2] = tuple[Tuple[T1], Tuple[T2]]
32
- type Select3[T1, T2, T3] = tuple[*Select2[T1, T2], Tuple[T3]]
33
- type Select4[T1, T2, T3, T4] = tuple[*Select3[T1, T2, T3], Tuple[T4]]
34
- type Select5[T1, T2, T3, T4, T5] = tuple[*Select4[T1, T2, T3, T4], Tuple[T5]]
35
- type Select6[T1, T2, T3, T4, T5, T6] = tuple[*Select5[T1, T2, T3, T4, T5], Tuple[T6]]
36
- type Select7[T1, T2, T3, T4, T5, T6, T7] = tuple[*Select6[T1, T2, T3, T4, T5, T6], Tuple[T7]]
37
- type Select8[T1, T2, T3, T4, T5, T6, T7, T8] = tuple[*Select7[T1, T2, T3, T4, T5, T6, T7], Tuple[T8]]
38
- type Select9[T1, T2, T3, T4, T5, T6, T7, T8, T9] = tuple[*Select8[T1, T2, T3, T4, T5, T6, T7, T8], Tuple[T9]]
39
- type Select10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10] = tuple[*Select9[T1, T2, T3, T4, T5, T6, T7, T8, T9], Tuple[T10]]
40
-
21
+ type Tuple[*T] = tuple[tuple[*T], ...]
41
22
  type WhereCondition[T, T1] = Callable[[T, T1], bool]
42
23
  type JoinCondition[T, T1] = tuple[T1, WhereCondition[T, T1], Optional[JoinType]]
43
24
 
44
25
 
45
- # TODOH [x]: This var is duplicated from 'src\ormlambda\databases\my_sql\clauses\create_database.py'
46
26
  type TypeExists = Literal["fail", "replace", "append"]
47
27
 
48
28
 
49
- type WhereTypes[LTable, LProp, RTable, RProp] = Union[
29
+ type WhereTypes[LTable] = Union[
50
30
  bool,
51
31
  Comparer,
52
- tuple[Comparer],
53
- Callable[[LTable], WhereTypes[LTable, LProp, RTable, RProp]],
32
+ Callable[[LTable], WhereTypes[LTable]],
33
+ Iterable[WhereTypes[LTable]],
54
34
  ]
55
35
 
56
36
 
@@ -1,88 +1,9 @@
1
- from .module_tree import ModuleTree # noqa: F401
2
- from .load_module import __load_module__ # noqa: F401
3
- import types
4
- import inspect
5
- from typing import Any, Literal, Optional, Sequence, overload, get_origin, TypeGuard, TypeAliasType
6
- from ormlambda.util.typing import LITERAL_TYPES, _AnnotationScanType
7
- from .plugin_loader import PluginLoader # noqa: F401
1
+ from .preloaded import preload_module as preload_module
2
+ from .preloaded import import_prefix as import_prefix
3
+ from . import preloaded as preloaded
8
4
 
5
+ from .langhelpers import get_cls_kwargs as get_cls_kwargs
6
+ from .langhelpers import PluginLoader as PluginLoader
9
7
 
10
- def _inspect_func_args(fn) -> tuple[list[str], bool]:
11
- try:
12
- co_varkeywords = inspect.CO_VARKEYWORDS
13
- except AttributeError:
14
- # https://docs.python.org/3/library/inspect.html
15
- # The flags are specific to CPython, and may not be defined in other
16
- # Python implementations. Furthermore, the flags are an implementation
17
- # detail, and can be removed or deprecated in future Python releases.
18
- spec = inspect.getfullargspec(fn)
19
- return spec[0], bool(spec[2])
20
- else:
21
- # use fn.__code__ plus flags to reduce method call overhead
22
- co = fn.__code__
23
- nargs = co.co_argcount
24
- return (
25
- list(co.co_varnames[:nargs]),
26
- bool(co.co_flags & co_varkeywords),
27
- )
28
-
29
-
30
- @overload
31
- def get_cls_kwargs(cls: type, *, _set: Optional[set[str]] = None, raiseerr: Literal[True] = ...) -> set[str]: ...
32
-
33
-
34
- @overload
35
- def get_cls_kwargs(cls: type, *, _set: Optional[set[str]] = None, raiseerr: Literal[False] = ...) -> Optional[set[str]]: ...
36
-
37
-
38
- def get_cls_kwargs(cls: type, *, _set: Optional[set[str]] = None, raiseerr: bool = False) -> Optional[set[str]]:
39
- """
40
- Get the keyword arguments for a class constructor.
41
- Args:
42
- cls: The class to inspect.
43
- _set: A set to store the keyword arguments.
44
- raiseerr: Whether to raise an error if the class is not found.
45
- Returns:
46
- A set of keyword arguments for the class constructor.
47
- """
48
- toplevel = _set is None
49
- if toplevel:
50
- _set = set()
51
- assert _set is not None
52
-
53
- ctr = cls.__dict__.get("__init__", False)
54
-
55
- has_init = ctr and isinstance(ctr, types.FunctionType) and isinstance(ctr.__code__, types.CodeType)
56
-
57
- if has_init:
58
- names, has_kw = _inspect_func_args(ctr)
59
- _set.update(names)
60
-
61
- if not has_kw and not toplevel:
62
- if raiseerr:
63
- raise TypeError(f"given cls {cls} doesn't have an __init__ method")
64
- else:
65
- return None
66
- else:
67
- has_kw = False
68
-
69
- if not has_init or has_kw:
70
- for c in cls.__bases__:
71
- if get_cls_kwargs(c, _set=_set) is None:
72
- break
73
-
74
- _set.discard("self")
75
- return _set
76
-
77
-
78
- def avoid_sql_injection(name: str):
79
- if any(char in name for char in [";", "--", "/*", "*/"]):
80
- raise ValueError("SQL injection detected")
81
-
82
-
83
- def is_literal(type_: Any) -> bool:
84
- return get_origin(type) in LITERAL_TYPES
85
-
86
-
87
- def is_pep695(type_: _AnnotationScanType) -> TypeGuard[TypeAliasType]:
88
- return isinstance(type_, TypeAliasType)
8
+ from .typing import is_literal as is_literal
9
+ from .typing import is_pep695 as is_pep695
@@ -0,0 +1,102 @@
1
+ import types
2
+ import inspect
3
+ from typing import Literal, Optional, overload, Callable
4
+ from types import ModuleType
5
+ from ormlambda import errors
6
+
7
+
8
+ def _inspect_func_args(fn) -> tuple[list[str], bool]:
9
+ try:
10
+ co_varkeywords = inspect.CO_VARKEYWORDS
11
+ except AttributeError:
12
+ # https://docs.python.org/3/library/inspect.html
13
+ # The flags are specific to CPython, and may not be defined in other
14
+ # Python implementations. Furthermore, the flags are an implementation
15
+ # detail, and can be removed or deprecated in future Python releases.
16
+ spec = inspect.getfullargspec(fn)
17
+ return spec[0], bool(spec[2])
18
+ else:
19
+ # use fn.__code__ plus flags to reduce method call overhead
20
+ co = fn.__code__
21
+ nargs = co.co_argcount
22
+ return (
23
+ list(co.co_varnames[:nargs]),
24
+ bool(co.co_flags & co_varkeywords),
25
+ )
26
+
27
+
28
+ @overload
29
+ def get_cls_kwargs(cls: type, *, _set: Optional[set[str]] = None, raiseerr: Literal[True] = ...) -> set[str]: ...
30
+
31
+
32
+ @overload
33
+ def get_cls_kwargs(cls: type, *, _set: Optional[set[str]] = None, raiseerr: Literal[False] = ...) -> Optional[set[str]]: ...
34
+
35
+
36
+ def get_cls_kwargs(cls: type, *, _set: Optional[set[str]] = None, raiseerr: bool = False) -> Optional[set[str]]:
37
+ """
38
+ Get the keyword arguments for a class constructor.
39
+ Args:
40
+ cls: The class to inspect.
41
+ _set: A set to store the keyword arguments.
42
+ raiseerr: Whether to raise an error if the class is not found.
43
+ Returns:
44
+ A set of keyword arguments for the class constructor.
45
+ """
46
+ toplevel = _set is None
47
+ if toplevel:
48
+ _set = set()
49
+ assert _set is not None
50
+
51
+ ctr = cls.__dict__.get("__init__", False)
52
+
53
+ has_init = ctr and isinstance(ctr, types.FunctionType) and isinstance(ctr.__code__, types.CodeType)
54
+
55
+ if has_init:
56
+ names, has_kw = _inspect_func_args(ctr)
57
+ _set.update(names)
58
+
59
+ if not has_kw and not toplevel:
60
+ if raiseerr:
61
+ raise TypeError(f"given cls {cls} doesn't have an __init__ method")
62
+ else:
63
+ return None
64
+ else:
65
+ has_kw = False
66
+
67
+ if not has_init or has_kw:
68
+ for c in cls.__bases__:
69
+ if get_cls_kwargs(c, _set=_set) is None:
70
+ break
71
+
72
+ _set.discard("self")
73
+ return _set
74
+
75
+
76
+ class PluginLoader:
77
+ def __init__(self, group: str, auto_fn: Optional[Callable[..., ModuleType]] = None):
78
+ self.group = group
79
+ self.impls: dict[str, ModuleType] = {}
80
+ self.auto_fn = auto_fn
81
+
82
+ def clear(self):
83
+ self.impls.clear()
84
+
85
+ def load(self, name: str) -> Optional[ModuleType]:
86
+ if name in self.impls:
87
+ return self.impls[name]()
88
+ if self.auto_fn:
89
+ loader = self.auto_fn(name)
90
+ if loader:
91
+ self.impls[name] = loader
92
+ return loader()
93
+ raise errors.NoSuchModuleError(f"Can't load plugin: {self.group}:{name}")
94
+
95
+ def register(self, name: str, modulepath: str, objname: str) -> None:
96
+ def load():
97
+ mod = __import__(modulepath)
98
+ for token in modulepath.split(".")[1:]:
99
+ mod = getattr(mod, token)
100
+ return getattr(mod, objname)
101
+
102
+ self.impls[name] = load
@@ -236,7 +236,7 @@ class ModuleTree:
236
236
  # we need to ensure that the object we going to add in table_list is the same
237
237
  for name, obj in table_class:
238
238
  if name == node.class_name:
239
- table_list.append(obj.create_table_query())
239
+ table_list.append(obj.create_table())
240
240
  return tuple(table_list)
241
241
 
242
242
  @staticmethod