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.
- ormlambda/__init__.py +3 -1
- ormlambda/caster/__init__.py +1 -1
- ormlambda/caster/caster.py +29 -12
- ormlambda/common/abstract_classes/clause_info_converter.py +65 -0
- ormlambda/common/abstract_classes/decomposition_query.py +27 -68
- ormlambda/common/abstract_classes/non_query_base.py +10 -8
- ormlambda/common/abstract_classes/query_base.py +3 -1
- ormlambda/common/errors/__init__.py +29 -0
- ormlambda/common/interfaces/ICustomAlias.py +1 -1
- ormlambda/common/interfaces/IQueryCommand.py +6 -2
- ormlambda/dialects/__init__.py +39 -0
- ormlambda/dialects/default/__init__.py +1 -0
- ormlambda/dialects/default/base.py +39 -0
- ormlambda/dialects/interface/__init__.py +1 -0
- ormlambda/dialects/interface/dialect.py +78 -0
- ormlambda/dialects/mysql/__init__.py +38 -0
- ormlambda/dialects/mysql/base.py +388 -0
- ormlambda/dialects/mysql/caster/caster.py +39 -0
- ormlambda/{databases/my_sql → dialects/mysql}/caster/types/__init__.py +1 -0
- ormlambda/dialects/mysql/caster/types/boolean.py +35 -0
- ormlambda/{databases/my_sql → dialects/mysql}/caster/types/bytes.py +7 -7
- ormlambda/{databases/my_sql → dialects/mysql}/caster/types/datetime.py +7 -7
- ormlambda/{databases/my_sql → dialects/mysql}/caster/types/float.py +7 -7
- ormlambda/{databases/my_sql → dialects/mysql}/caster/types/int.py +7 -7
- ormlambda/{databases/my_sql → dialects/mysql}/caster/types/iterable.py +7 -7
- ormlambda/{databases/my_sql → dialects/mysql}/caster/types/none.py +8 -7
- ormlambda/{databases/my_sql → dialects/mysql}/caster/types/point.py +4 -4
- ormlambda/{databases/my_sql → dialects/mysql}/caster/types/string.py +7 -7
- ormlambda/{databases/my_sql → dialects/mysql}/clauses/ST_AsText.py +8 -7
- ormlambda/{databases/my_sql → dialects/mysql}/clauses/ST_Contains.py +10 -5
- ormlambda/dialects/mysql/clauses/__init__.py +13 -0
- ormlambda/dialects/mysql/clauses/count.py +33 -0
- ormlambda/dialects/mysql/clauses/delete.py +9 -0
- ormlambda/dialects/mysql/clauses/group_by.py +17 -0
- ormlambda/dialects/mysql/clauses/having.py +12 -0
- ormlambda/dialects/mysql/clauses/insert.py +9 -0
- ormlambda/dialects/mysql/clauses/joins.py +14 -0
- ormlambda/dialects/mysql/clauses/limit.py +6 -0
- ormlambda/dialects/mysql/clauses/offset.py +6 -0
- ormlambda/dialects/mysql/clauses/order.py +8 -0
- ormlambda/dialects/mysql/clauses/update.py +8 -0
- ormlambda/dialects/mysql/clauses/upsert.py +9 -0
- ormlambda/dialects/mysql/clauses/where.py +7 -0
- ormlambda/dialects/mysql/mysqlconnector.py +46 -0
- ormlambda/dialects/mysql/repository/__init__.py +1 -0
- ormlambda/dialects/mysql/repository/repository.py +212 -0
- ormlambda/dialects/mysql/types.py +732 -0
- ormlambda/dialects/sqlite/__init__.py +5 -0
- ormlambda/dialects/sqlite/base.py +47 -0
- ormlambda/dialects/sqlite/pysqlite.py +32 -0
- ormlambda/engine/__init__.py +1 -0
- ormlambda/engine/base.py +77 -0
- ormlambda/engine/create.py +9 -23
- ormlambda/engine/url.py +34 -19
- ormlambda/env.py +30 -0
- ormlambda/errors.py +17 -0
- ormlambda/model/base_model.py +7 -9
- ormlambda/repository/base_repository.py +36 -5
- ormlambda/repository/interfaces/IRepositoryBase.py +119 -12
- ormlambda/repository/response.py +134 -0
- ormlambda/sql/clause_info/__init__.py +2 -1
- ormlambda/sql/clause_info/aggregate_function_base.py +96 -0
- ormlambda/sql/clause_info/clause_info.py +35 -115
- ormlambda/sql/clause_info/interface/IClauseInfo.py +37 -0
- ormlambda/sql/clause_info/interface/__init__.py +1 -0
- ormlambda/sql/clauses/__init__.py +14 -0
- ormlambda/{databases/my_sql → sql}/clauses/alias.py +23 -6
- ormlambda/{databases/my_sql → sql}/clauses/count.py +15 -1
- ormlambda/{databases/my_sql → sql}/clauses/delete.py +22 -7
- ormlambda/sql/clauses/group_by.py +30 -0
- ormlambda/{databases/my_sql → sql}/clauses/having.py +7 -2
- ormlambda/{databases/my_sql → sql}/clauses/insert.py +16 -9
- ormlambda/sql/clauses/interfaces/__init__.py +5 -0
- ormlambda/sql/clauses/join/__init__.py +1 -0
- ormlambda/{databases/my_sql → sql/clauses/join}/join_context.py +15 -7
- ormlambda/{databases/my_sql → sql}/clauses/joins.py +29 -19
- ormlambda/sql/clauses/limit.py +15 -0
- ormlambda/sql/clauses/offset.py +15 -0
- ormlambda/{databases/my_sql → sql}/clauses/order.py +14 -24
- ormlambda/{databases/my_sql → sql}/clauses/select.py +14 -13
- ormlambda/{databases/my_sql → sql}/clauses/update.py +24 -11
- ormlambda/{databases/my_sql → sql}/clauses/upsert.py +19 -10
- ormlambda/{databases/my_sql → sql}/clauses/where.py +28 -8
- ormlambda/sql/column/__init__.py +1 -0
- ormlambda/sql/{column.py → column/column.py} +85 -22
- ormlambda/sql/comparer.py +51 -37
- ormlambda/sql/compiler.py +668 -0
- ormlambda/sql/ddl.py +82 -0
- ormlambda/sql/elements.py +36 -0
- ormlambda/sql/foreign_key.py +61 -39
- ormlambda/{databases/my_sql → sql}/functions/concat.py +13 -5
- ormlambda/{databases/my_sql → sql}/functions/max.py +9 -4
- ormlambda/{databases/my_sql → sql}/functions/min.py +9 -13
- ormlambda/{databases/my_sql → sql}/functions/sum.py +8 -10
- ormlambda/sql/sqltypes.py +647 -0
- ormlambda/sql/table/__init__.py +1 -1
- ormlambda/sql/table/table.py +175 -0
- ormlambda/sql/table/table_constructor.py +1 -208
- ormlambda/sql/type_api.py +35 -0
- ormlambda/sql/types.py +3 -1
- ormlambda/sql/visitors.py +74 -0
- ormlambda/statements/__init__.py +1 -0
- ormlambda/statements/base_statement.py +34 -40
- ormlambda/statements/interfaces/IStatements.py +28 -21
- ormlambda/statements/query_builder.py +163 -0
- ormlambda/{databases/my_sql → statements}/statements.py +68 -210
- ormlambda/statements/types.py +2 -2
- ormlambda/types/__init__.py +24 -0
- ormlambda/types/metadata.py +42 -0
- ormlambda/util/__init__.py +87 -0
- ormlambda/{utils → util}/module_tree/dynamic_module.py +4 -3
- ormlambda/util/plugin_loader.py +32 -0
- ormlambda/util/typing.py +6 -0
- ormlambda-3.34.0.dist-info/AUTHORS +32 -0
- {ormlambda-3.11.2.dist-info → ormlambda-3.34.0.dist-info}/METADATA +56 -10
- ormlambda-3.34.0.dist-info/RECORD +152 -0
- ormlambda/components/__init__.py +0 -4
- ormlambda/components/delete/__init__.py +0 -2
- ormlambda/components/delete/abstract_delete.py +0 -17
- ormlambda/components/insert/__init__.py +0 -2
- ormlambda/components/insert/abstract_insert.py +0 -25
- ormlambda/components/select/__init__.py +0 -1
- ormlambda/components/update/__init__.py +0 -2
- ormlambda/components/update/abstract_update.py +0 -29
- ormlambda/components/upsert/__init__.py +0 -2
- ormlambda/components/upsert/abstract_upsert.py +0 -25
- ormlambda/databases/__init__.py +0 -5
- ormlambda/databases/my_sql/__init__.py +0 -4
- ormlambda/databases/my_sql/caster/caster.py +0 -39
- ormlambda/databases/my_sql/clauses/__init__.py +0 -20
- ormlambda/databases/my_sql/clauses/create_database.py +0 -35
- ormlambda/databases/my_sql/clauses/drop_database.py +0 -17
- ormlambda/databases/my_sql/clauses/drop_table.py +0 -23
- ormlambda/databases/my_sql/clauses/group_by.py +0 -31
- ormlambda/databases/my_sql/clauses/limit.py +0 -17
- ormlambda/databases/my_sql/clauses/offset.py +0 -17
- ormlambda/databases/my_sql/repository/__init__.py +0 -1
- ormlambda/databases/my_sql/repository/repository.py +0 -351
- ormlambda/engine/template.py +0 -47
- ormlambda/sql/dtypes.py +0 -94
- ormlambda/utils/__init__.py +0 -1
- ormlambda-3.11.2.dist-info/RECORD +0 -120
- /ormlambda/{databases/my_sql → dialects/mysql}/caster/__init__.py +0 -0
- /ormlambda/{databases/my_sql/types.py → dialects/mysql/repository/pool_types.py} +0 -0
- /ormlambda/{components/delete → sql/clauses/interfaces}/IDelete.py +0 -0
- /ormlambda/{components/insert → sql/clauses/interfaces}/IInsert.py +0 -0
- /ormlambda/{components/select → sql/clauses/interfaces}/ISelect.py +0 -0
- /ormlambda/{components/update → sql/clauses/interfaces}/IUpdate.py +0 -0
- /ormlambda/{components/upsert → sql/clauses/interfaces}/IUpsert.py +0 -0
- /ormlambda/{databases/my_sql → sql}/functions/__init__.py +0 -0
- /ormlambda/{utils → util}/module_tree/__init__.py +0 -0
- /ormlambda/{utils → util}/module_tree/dfs_traversal.py +0 -0
- {ormlambda-3.11.2.dist-info → ormlambda-3.34.0.dist-info}/LICENSE +0 -0
- {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
|
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.
|
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](
|
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:
|
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:
|
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
|