ormlambda 3.11.2__py3-none-any.whl → 3.34.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 (154) hide show
  1. ormlambda/__init__.py +3 -1
  2. ormlambda/caster/__init__.py +1 -1
  3. ormlambda/caster/caster.py +29 -12
  4. ormlambda/common/abstract_classes/clause_info_converter.py +65 -0
  5. ormlambda/common/abstract_classes/decomposition_query.py +27 -68
  6. ormlambda/common/abstract_classes/non_query_base.py +10 -8
  7. ormlambda/common/abstract_classes/query_base.py +3 -1
  8. ormlambda/common/errors/__init__.py +29 -0
  9. ormlambda/common/interfaces/ICustomAlias.py +1 -1
  10. ormlambda/common/interfaces/IQueryCommand.py +6 -2
  11. ormlambda/dialects/__init__.py +39 -0
  12. ormlambda/dialects/default/__init__.py +1 -0
  13. ormlambda/dialects/default/base.py +39 -0
  14. ormlambda/dialects/interface/__init__.py +1 -0
  15. ormlambda/dialects/interface/dialect.py +78 -0
  16. ormlambda/dialects/mysql/__init__.py +38 -0
  17. ormlambda/dialects/mysql/base.py +388 -0
  18. ormlambda/dialects/mysql/caster/caster.py +39 -0
  19. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/__init__.py +1 -0
  20. ormlambda/dialects/mysql/caster/types/boolean.py +35 -0
  21. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/bytes.py +7 -7
  22. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/datetime.py +7 -7
  23. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/float.py +7 -7
  24. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/int.py +7 -7
  25. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/iterable.py +7 -7
  26. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/none.py +8 -7
  27. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/point.py +4 -4
  28. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/string.py +7 -7
  29. ormlambda/{databases/my_sql → dialects/mysql}/clauses/ST_AsText.py +8 -7
  30. ormlambda/{databases/my_sql → dialects/mysql}/clauses/ST_Contains.py +10 -5
  31. ormlambda/dialects/mysql/clauses/__init__.py +13 -0
  32. ormlambda/dialects/mysql/clauses/count.py +33 -0
  33. ormlambda/dialects/mysql/clauses/delete.py +9 -0
  34. ormlambda/dialects/mysql/clauses/group_by.py +17 -0
  35. ormlambda/dialects/mysql/clauses/having.py +12 -0
  36. ormlambda/dialects/mysql/clauses/insert.py +9 -0
  37. ormlambda/dialects/mysql/clauses/joins.py +14 -0
  38. ormlambda/dialects/mysql/clauses/limit.py +6 -0
  39. ormlambda/dialects/mysql/clauses/offset.py +6 -0
  40. ormlambda/dialects/mysql/clauses/order.py +8 -0
  41. ormlambda/dialects/mysql/clauses/update.py +8 -0
  42. ormlambda/dialects/mysql/clauses/upsert.py +9 -0
  43. ormlambda/dialects/mysql/clauses/where.py +7 -0
  44. ormlambda/dialects/mysql/mysqlconnector.py +46 -0
  45. ormlambda/dialects/mysql/repository/__init__.py +1 -0
  46. ormlambda/dialects/mysql/repository/repository.py +212 -0
  47. ormlambda/dialects/mysql/types.py +732 -0
  48. ormlambda/dialects/sqlite/__init__.py +5 -0
  49. ormlambda/dialects/sqlite/base.py +47 -0
  50. ormlambda/dialects/sqlite/pysqlite.py +32 -0
  51. ormlambda/engine/__init__.py +1 -0
  52. ormlambda/engine/base.py +77 -0
  53. ormlambda/engine/create.py +9 -23
  54. ormlambda/engine/url.py +34 -19
  55. ormlambda/env.py +30 -0
  56. ormlambda/errors.py +17 -0
  57. ormlambda/model/base_model.py +7 -9
  58. ormlambda/repository/base_repository.py +36 -5
  59. ormlambda/repository/interfaces/IRepositoryBase.py +119 -12
  60. ormlambda/repository/response.py +134 -0
  61. ormlambda/sql/clause_info/__init__.py +2 -1
  62. ormlambda/sql/clause_info/aggregate_function_base.py +96 -0
  63. ormlambda/sql/clause_info/clause_info.py +35 -115
  64. ormlambda/sql/clause_info/interface/IClauseInfo.py +37 -0
  65. ormlambda/sql/clause_info/interface/__init__.py +1 -0
  66. ormlambda/sql/clauses/__init__.py +14 -0
  67. ormlambda/{databases/my_sql → sql}/clauses/alias.py +23 -6
  68. ormlambda/{databases/my_sql → sql}/clauses/count.py +15 -1
  69. ormlambda/{databases/my_sql → sql}/clauses/delete.py +22 -7
  70. ormlambda/sql/clauses/group_by.py +30 -0
  71. ormlambda/{databases/my_sql → sql}/clauses/having.py +7 -2
  72. ormlambda/{databases/my_sql → sql}/clauses/insert.py +16 -9
  73. ormlambda/sql/clauses/interfaces/__init__.py +5 -0
  74. ormlambda/sql/clauses/join/__init__.py +1 -0
  75. ormlambda/{databases/my_sql → sql/clauses/join}/join_context.py +15 -7
  76. ormlambda/{databases/my_sql → sql}/clauses/joins.py +29 -19
  77. ormlambda/sql/clauses/limit.py +15 -0
  78. ormlambda/sql/clauses/offset.py +15 -0
  79. ormlambda/{databases/my_sql → sql}/clauses/order.py +14 -24
  80. ormlambda/{databases/my_sql → sql}/clauses/select.py +14 -13
  81. ormlambda/{databases/my_sql → sql}/clauses/update.py +24 -11
  82. ormlambda/{databases/my_sql → sql}/clauses/upsert.py +19 -10
  83. ormlambda/{databases/my_sql → sql}/clauses/where.py +28 -8
  84. ormlambda/sql/column/__init__.py +1 -0
  85. ormlambda/sql/{column.py → column/column.py} +85 -22
  86. ormlambda/sql/comparer.py +51 -37
  87. ormlambda/sql/compiler.py +668 -0
  88. ormlambda/sql/ddl.py +82 -0
  89. ormlambda/sql/elements.py +36 -0
  90. ormlambda/sql/foreign_key.py +61 -39
  91. ormlambda/{databases/my_sql → sql}/functions/concat.py +13 -5
  92. ormlambda/{databases/my_sql → sql}/functions/max.py +9 -4
  93. ormlambda/{databases/my_sql → sql}/functions/min.py +9 -13
  94. ormlambda/{databases/my_sql → sql}/functions/sum.py +8 -10
  95. ormlambda/sql/sqltypes.py +647 -0
  96. ormlambda/sql/table/__init__.py +1 -1
  97. ormlambda/sql/table/table.py +175 -0
  98. ormlambda/sql/table/table_constructor.py +1 -208
  99. ormlambda/sql/type_api.py +35 -0
  100. ormlambda/sql/types.py +3 -1
  101. ormlambda/sql/visitors.py +74 -0
  102. ormlambda/statements/__init__.py +1 -0
  103. ormlambda/statements/base_statement.py +34 -40
  104. ormlambda/statements/interfaces/IStatements.py +28 -21
  105. ormlambda/statements/query_builder.py +163 -0
  106. ormlambda/{databases/my_sql → statements}/statements.py +68 -210
  107. ormlambda/statements/types.py +2 -2
  108. ormlambda/types/__init__.py +24 -0
  109. ormlambda/types/metadata.py +42 -0
  110. ormlambda/util/__init__.py +87 -0
  111. ormlambda/{utils → util}/module_tree/dynamic_module.py +4 -3
  112. ormlambda/util/plugin_loader.py +32 -0
  113. ormlambda/util/typing.py +6 -0
  114. ormlambda-3.34.0.dist-info/AUTHORS +32 -0
  115. {ormlambda-3.11.2.dist-info → ormlambda-3.34.0.dist-info}/METADATA +56 -10
  116. ormlambda-3.34.0.dist-info/RECORD +152 -0
  117. ormlambda/components/__init__.py +0 -4
  118. ormlambda/components/delete/__init__.py +0 -2
  119. ormlambda/components/delete/abstract_delete.py +0 -17
  120. ormlambda/components/insert/__init__.py +0 -2
  121. ormlambda/components/insert/abstract_insert.py +0 -25
  122. ormlambda/components/select/__init__.py +0 -1
  123. ormlambda/components/update/__init__.py +0 -2
  124. ormlambda/components/update/abstract_update.py +0 -29
  125. ormlambda/components/upsert/__init__.py +0 -2
  126. ormlambda/components/upsert/abstract_upsert.py +0 -25
  127. ormlambda/databases/__init__.py +0 -5
  128. ormlambda/databases/my_sql/__init__.py +0 -4
  129. ormlambda/databases/my_sql/caster/caster.py +0 -39
  130. ormlambda/databases/my_sql/clauses/__init__.py +0 -20
  131. ormlambda/databases/my_sql/clauses/create_database.py +0 -35
  132. ormlambda/databases/my_sql/clauses/drop_database.py +0 -17
  133. ormlambda/databases/my_sql/clauses/drop_table.py +0 -23
  134. ormlambda/databases/my_sql/clauses/group_by.py +0 -31
  135. ormlambda/databases/my_sql/clauses/limit.py +0 -17
  136. ormlambda/databases/my_sql/clauses/offset.py +0 -17
  137. ormlambda/databases/my_sql/repository/__init__.py +0 -1
  138. ormlambda/databases/my_sql/repository/repository.py +0 -351
  139. ormlambda/engine/template.py +0 -47
  140. ormlambda/sql/dtypes.py +0 -94
  141. ormlambda/utils/__init__.py +0 -1
  142. ormlambda-3.11.2.dist-info/RECORD +0 -120
  143. /ormlambda/{databases/my_sql → dialects/mysql}/caster/__init__.py +0 -0
  144. /ormlambda/{databases/my_sql/types.py → dialects/mysql/repository/pool_types.py} +0 -0
  145. /ormlambda/{components/delete → sql/clauses/interfaces}/IDelete.py +0 -0
  146. /ormlambda/{components/insert → sql/clauses/interfaces}/IInsert.py +0 -0
  147. /ormlambda/{components/select → sql/clauses/interfaces}/ISelect.py +0 -0
  148. /ormlambda/{components/update → sql/clauses/interfaces}/IUpdate.py +0 -0
  149. /ormlambda/{components/upsert → sql/clauses/interfaces}/IUpsert.py +0 -0
  150. /ormlambda/{databases/my_sql → sql}/functions/__init__.py +0 -0
  151. /ormlambda/{utils → util}/module_tree/__init__.py +0 -0
  152. /ormlambda/{utils → util}/module_tree/dfs_traversal.py +0 -0
  153. {ormlambda-3.11.2.dist-info → ormlambda-3.34.0.dist-info}/LICENSE +0 -0
  154. {ormlambda-3.11.2.dist-info → ormlambda-3.34.0.dist-info}/WHEEL +0 -0
@@ -1,8 +1,7 @@
1
1
  from __future__ import annotations
2
2
  from typing import Any, Callable, Optional, Type, overload, TYPE_CHECKING
3
3
  from enum import Enum
4
- from abc import abstractmethod, ABC
5
-
4
+ from abc import abstractmethod
6
5
 
7
6
 
8
7
  if TYPE_CHECKING:
@@ -10,12 +9,11 @@ if TYPE_CHECKING:
10
9
  from ormlambda import Table
11
10
  from ormlambda.sql.clause_info import IAggregate
12
11
  from ormlambda.sql.types import TupleJoinType, ColumnType
13
- from ormlambda.databases.my_sql.join_context import JoinContext
12
+ from ormlambda.sql.clauses.join import JoinContext
14
13
  from ormlambda.common.enums import JoinType
15
14
  from ormlambda.sql.clause_info import ClauseInfo
16
15
  from ormlambda.sql.types import AliasType
17
16
 
18
-
19
17
  from ..types import (
20
18
  OrderTypes,
21
19
  Tuple,
@@ -32,12 +30,16 @@ from ..types import (
32
30
  WhereTypes,
33
31
  SelectCols,
34
32
  )
33
+ from ormlambda.sql.elements import Element
35
34
 
36
35
 
37
- class IStatements[T: Table](ABC):
36
+ class IStatements[T: Table](Element):
38
37
  @abstractmethod
39
38
  def create_table(self, if_exists: TypeExists = "fail") -> None: ...
40
39
 
40
+ @abstractmethod
41
+ def drop_table(self) -> None: ...
42
+
41
43
  # #TODOL [ ]: We must to implement this mehtod
42
44
  # @abstractmethod
43
45
  # def drop_table(self)->None: ...
@@ -249,33 +251,33 @@ class IStatements[T: Table](ABC):
249
251
  # @overload
250
252
  # def select[TFlavour](self, selector: Optional[Callable[[T], tuple]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour], by: Optional[Enum] = ..., **kwargs) -> TFlavour: ...
251
253
  @overload
252
- def select[TRes](self, selector: SelectorFlavourType[T, TRes] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., **kwargs) -> tuple[TRes, ...]: ...
254
+ def select[TRes](self, selector: SelectorFlavourType[T, TRes] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[TRes, ...]: ...
253
255
  @overload
254
- def select[*TRes](self, selector: SelectorFlavourType[T, tuple[*TRes]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., **kwargs) -> tuple[tuple[*TRes]]: ...
256
+ def select[*TRes](self, selector: SelectorFlavourType[T, tuple[*TRes]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[tuple[*TRes]]: ...
255
257
  @overload
256
- def select[TFlavour](self, selector: SelectorFlavourType[T, tuple] = ..., *, flavour: Type[TFlavour], by: Optional[Enum] = ..., **kwargs) -> tuple[TFlavour, ...]: ...
258
+ def select[TFlavour](self, selector: SelectorFlavourType[T, tuple] = ..., *, flavour: Type[TFlavour], by: Optional[Enum] = ..., alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[TFlavour, ...]: ...
257
259
 
258
260
  @abstractmethod
259
- def select[TValue, TFlavour, P](self, selector: SelectorFlavourType[T, tuple[TValue, P]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour] = ..., by: JoinType = ..., **kwargs): ...
261
+ def select[TValue, TFlavour, P](self, selector: SelectorFlavourType[T, tuple[TValue, P]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour] = ..., by: JoinType = ..., alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs): ...
260
262
 
261
263
  # endregion
262
264
  # region select_one
263
265
  @overload
264
266
  def select_one(self) -> T: ...
265
267
  @overload
266
- def select_one[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
268
+ def select_one[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
267
269
  @overload
268
270
  def select_one[T1](self, selector: SelectorOneType[T, T1 | tuple[T1]], *, by: Optional[Enum] = ...) -> T1: ...
269
271
  @overload
270
272
  def select_one[*TRes](self, selector: SelectorOneType[T, tuple[*TRes]], *, by: Optional[Enum] = ...) -> tuple[*TRes]: ...
271
273
  @overload
272
- def select_one[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, **kwargs) -> T1: ...
274
+ def select_one[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> T1: ...
273
275
  @overload
274
- def select_one[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
276
+ def select_one[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
275
277
  @overload
276
- def select_one[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], **kwargs) -> tuple[*TRest]: ...
278
+ def select_one[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[*TRest]: ...
277
279
  @overload
278
- def select_one[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
280
+ def select_one[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
279
281
  @abstractmethod
280
282
  def select_one[TValue, TFlavour, *TRest](
281
283
  self,
@@ -295,15 +297,15 @@ class IStatements[T: Table](ABC):
295
297
  @overload
296
298
  def first[*TRes](self, selector: SelectorOneType[T, tuple[*TRes]], *, by: Optional[Enum] = ...) -> tuple[*TRes]: ...
297
299
  @overload
298
- def first[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
300
+ def first[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
299
301
  @overload
300
- def first[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, **kwargs) -> T1: ...
302
+ def first[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> T1: ...
301
303
  @overload
302
- def first[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
304
+ def first[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
303
305
  @overload
304
- def first[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], **kwargs) -> tuple[*TRest]: ...
306
+ def first[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[*TRest]: ...
305
307
  @overload
306
- def first[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
308
+ def first[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
307
309
  @abstractmethod
308
310
  def first[TValue, TFlavour, *TRest](
309
311
  self,
@@ -316,13 +318,17 @@ class IStatements[T: Table](ABC):
316
318
  # endregion
317
319
 
318
320
  # region groupby
321
+ @overload
322
+ def groupby[TRepo](self, column: list[SelectCols[T, TRepo]]) -> IStatements[T]: ...
323
+ @overload
324
+ def groupby[TRepo](self, column: SelectCols[T, TRepo]) -> IStatements[T]: ...
319
325
  @abstractmethod
320
- def groupby[TRepo](self, column: Callable[[T], TRepo]) -> IStatements[T]: ...
326
+ def groupby[TRepo](self, column: list[SelectCols[T, TRepo]] | SelectCols[T, TRepo]) -> IStatements[T]: ...
321
327
 
322
328
  # endregion
323
329
 
324
330
  @abstractmethod
325
- def alias[TProp](self, column: ColumnType[TProp], alias: AliasType[ClauseInfo[T]]) -> ClauseInfo[T]: ...
331
+ def alias[TProp](self, column: SelectCols[T, TProp], alias: AliasType[ClauseInfo[T]]) -> ClauseInfo[T]: ...
326
332
 
327
333
 
328
334
  class IStatements_two_generic[T, TPool](IStatements[T]):
@@ -331,6 +337,7 @@ class IStatements_two_generic[T, TPool](IStatements[T]):
331
337
  def repository(self) -> BaseRepository[TPool]: ...
332
338
 
333
339
  @property
340
+ @abstractmethod
334
341
  def query(self) -> str: ...
335
342
 
336
343
  @property
@@ -0,0 +1,163 @@
1
+ from __future__ import annotations
2
+ from typing import Iterable, TypedDict, Optional, TYPE_CHECKING
3
+
4
+ from ormlambda.sql.clause_info.clause_info_context import ClauseInfoContext
5
+ from ormlambda.sql.clauses import JoinSelector
6
+ from ormlambda import ForeignKey
7
+
8
+ from ormlambda.common.interfaces import IQuery
9
+
10
+
11
+ from ormlambda.sql.clause_info import ClauseInfo
12
+
13
+ if TYPE_CHECKING:
14
+ from ..sql.clauses import Limit as Limit
15
+ from ..sql.clauses import Offset as Offset
16
+ from ..sql.clauses import Order as Order
17
+ from ..sql.clauses import Select as Select
18
+
19
+ from ..sql.clauses import GroupBy as GroupBy
20
+
21
+ from ormlambda.dialects import Dialect
22
+
23
+ from ..sql.clauses import Where as Where
24
+ from ..sql.clauses import Having as Having
25
+ from ormlambda.common.enums import JoinType
26
+ from ormlambda.sql.elements import ClauseElement
27
+
28
+
29
+ class OrderType(TypedDict):
30
+ Select: Select
31
+ JoinSelector: JoinSelector
32
+ Where: Where
33
+ Order: Order
34
+ GroupBy: GroupBy
35
+ Having: Having
36
+ Limit: Limit
37
+ Offset: Offset
38
+
39
+
40
+ class QueryBuilder(IQuery):
41
+ __order__: tuple[str, ...] = ("Select", "JoinSelector", "Where", "GroupBy", "Having", "Order", "Limit", "Offset")
42
+
43
+ def __init__(self, dialect: Dialect, by: JoinType = JoinType.INNER_JOIN):
44
+ self.dialect = dialect
45
+ self._context = ClauseInfoContext()
46
+ self._query_list: OrderType = {}
47
+ self._by = by
48
+
49
+ self._joins: Optional[IQuery] = None
50
+ self._select: Optional[IQuery] = None
51
+ self._where: Optional[IQuery] = None
52
+ self._order: Optional[IQuery] = None
53
+ self._group_by: Optional[IQuery] = None
54
+ self._limit: Optional[IQuery] = None
55
+ self._offset: Optional[IQuery] = None
56
+
57
+ def add_statement[T](self, clause: ClauseInfo[T]):
58
+ self.update_context(clause)
59
+ self._query_list[type(clause).__name__] = clause
60
+
61
+ @property
62
+ def by(self) -> JoinType:
63
+ return self._by
64
+
65
+ @by.setter
66
+ def by(self, value: JoinType) -> None:
67
+ self._by = value
68
+
69
+ @property
70
+ def JOINS(self) -> Optional[set[JoinSelector]]:
71
+ return self._joins
72
+
73
+ @property
74
+ def SELECT(self) -> ClauseElement:
75
+ return self._query_list.get("Select", None)
76
+
77
+ @property
78
+ def WHERE(self) -> ClauseElement:
79
+ where = self._query_list.get("Where", None)
80
+ if not isinstance(where, Iterable):
81
+ if not where:
82
+ return ()
83
+ return (where,)
84
+ return where
85
+
86
+ @property
87
+ def ORDER(self) -> ClauseElement:
88
+ return self._query_list.get("Order", None)
89
+
90
+ @property
91
+ def GROUP_BY(self) -> ClauseElement:
92
+ return self._query_list.get("GroupBy", None)
93
+
94
+ @property
95
+ def HAVING(self) -> ClauseElement:
96
+ where = self._query_list.get("Having", None)
97
+ if not isinstance(where, Iterable):
98
+ if not where:
99
+ return ()
100
+ return (where,)
101
+ return where
102
+
103
+ @property
104
+ def LIMIT(self) -> ClauseElement:
105
+ return self._query_list.get("Limit", None)
106
+
107
+ @property
108
+ def OFFSET(self) -> ClauseElement:
109
+ return self._query_list.get("Offset", None)
110
+
111
+ def query(self, dialect: Dialect, **kwargs) -> str:
112
+ # COMMENT: (select.query, query)We must first create an alias for 'FROM' and then define all the remaining clauses.
113
+ # This order is mandatory because it adds the clause name to the context when accessing the .query property of 'FROM'
114
+
115
+ extract_joins = self.pop_tables_and_create_joins_from_ForeignKey(self._by)
116
+
117
+ JOINS = self.stringify_foreign_key(extract_joins, " ")
118
+ query_list: tuple[str, ...] = (
119
+ self.SELECT.compile(dialect).string,
120
+ JOINS,
121
+ Where.join_condition(self.WHERE, True, self._context, dialect=dialect) if self.WHERE else None,
122
+ self.GROUP_BY.compile(dialect).string if self.GROUP_BY else None,
123
+ Having.join_condition(self.HAVING, True, self._context, dialect=dialect) if self.HAVING else None,
124
+ self.ORDER.compile(dialect).string if self.ORDER else None,
125
+ self.LIMIT.compile(dialect).string if self.LIMIT else None,
126
+ self.OFFSET.compile(dialect).string if self.OFFSET else None,
127
+ )
128
+ return " ".join([x for x in query_list if x])
129
+
130
+ def stringify_foreign_key(self, joins: set[JoinSelector], sep: str = "\n") -> Optional[str]:
131
+ if not joins:
132
+ return None
133
+ sorted_joins = JoinSelector.sort_join_selectors(joins)
134
+ return f"{sep}".join([join.query(self.dialect) for join in sorted_joins])
135
+
136
+ def pop_tables_and_create_joins_from_ForeignKey(self, by: JoinType = JoinType.INNER_JOIN) -> set[JoinSelector]:
137
+ # When we applied filters in any table that we wont select any column, we need to add manually all neccessary joins to achieve positive result.
138
+ if not ForeignKey.stored_calls:
139
+ return None
140
+
141
+ joins = set()
142
+ # Always it's gonna be a set of two
143
+ # FIXME [x]: Resolved when we get Compare object instead ClauseInfo. For instance, when we have multiples condition using '&' or '|'
144
+ for fk in ForeignKey.stored_calls.copy():
145
+ fk = ForeignKey.stored_calls.pop(fk)
146
+ fk_alias = fk.get_alias(self.dialect)
147
+ self._context._add_table_alias(fk.tright, fk_alias)
148
+ join = JoinSelector(fk.resolved_function(self._context), by, context=self._context, alias=fk_alias, dialect=self.dialect)
149
+ joins.add(join)
150
+
151
+ return joins
152
+
153
+ def clear(self) -> None:
154
+ self.__init__(self.dialect, self.by)
155
+ return None
156
+
157
+ def update_context(self, clause: ClauseInfo) -> None:
158
+ if not hasattr(clause, "context"):
159
+ return None
160
+
161
+ if clause.context is not None:
162
+ self._context.update(clause.context)
163
+ clause.context = self._context