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
@@ -0,0 +1,134 @@
1
+ from __future__ import annotations
2
+ from typing import Type, Any, TYPE_CHECKING, Optional
3
+ from ormlambda.dialects.interface.dialect import Dialect
4
+ import shapely as shp
5
+
6
+ # Custom libraries
7
+ from ormlambda.sql.clauses import Alias
8
+
9
+ if TYPE_CHECKING:
10
+ from ormlambda.common.abstract_classes.decomposition_query import ClauseInfo
11
+ from ormlambda import Table
12
+ from ormlambda.sql.clauses import Select
13
+
14
+
15
+ type TResponse[TFlavour, *Ts] = TFlavour | tuple[dict[str, tuple[*Ts]]] | tuple[tuple[*Ts]] | tuple[TFlavour]
16
+
17
+
18
+ class Response[TFlavour, *Ts]:
19
+ def __init__(
20
+ self,
21
+ dialect: Dialect,
22
+ response_values: list[tuple[*Ts]],
23
+ columns: tuple[str],
24
+ flavour: Type[TFlavour],
25
+ select: Optional[Select] = None,
26
+ ) -> None:
27
+ self._dialect: Dialect = dialect
28
+ self._response_values: list[tuple[*Ts]] = response_values
29
+ self._columns: tuple[str] = columns
30
+ self._flavour: Type[TFlavour] = flavour
31
+ self._select: Select = select
32
+
33
+ self._response_values_index: int = len(self._response_values)
34
+
35
+ self._caster = dialect.caster()
36
+
37
+ @property
38
+ def is_one(self) -> bool:
39
+ return self._response_values_index == 1
40
+
41
+ @property
42
+ def is_there_response(self) -> bool:
43
+ return self._response_values_index != 0
44
+
45
+ @property
46
+ def is_many(self) -> bool:
47
+ return self._response_values_index > 1
48
+
49
+ def response(self, **kwargs) -> TResponse[TFlavour, *Ts]:
50
+ if not self.is_there_response:
51
+ return tuple([])
52
+
53
+ # Cast data using caster
54
+ cleaned_response = self._response_values
55
+
56
+ if self._select is not None:
57
+ cleaned_response = self._clean_response()
58
+
59
+ cast_flavour = self._cast_to_flavour(cleaned_response, **kwargs)
60
+
61
+ return tuple(cast_flavour)
62
+
63
+ def _cast_to_flavour(self, data: list[tuple[*Ts]], **kwargs) -> list[dict[str, tuple[*Ts]]] | list[tuple[*Ts]] | list[TFlavour]:
64
+ def _dict(**kwargs) -> list[dict[str, tuple[*Ts]]]:
65
+ nonlocal data
66
+ return [dict(zip(self._columns, x)) for x in data]
67
+
68
+ def _tuple(**kwargs) -> list[tuple[*Ts]]:
69
+ nonlocal data
70
+ return data
71
+
72
+ def _set(**kwargs) -> list[set]:
73
+ nonlocal data
74
+ for d in data:
75
+ n = len(d)
76
+ for i in range(n):
77
+ try:
78
+ hash(d[i])
79
+ except TypeError:
80
+ raise TypeError(f"unhashable type '{type(d[i])}' found in '{type(d)}' when attempting to cast the result into a '{set.__name__}' object")
81
+ return [set(x) for x in data]
82
+
83
+ def _list(**kwargs) -> list[list]:
84
+ nonlocal data
85
+ return [list(x) for x in data]
86
+
87
+ def _default(**kwargs) -> list[TFlavour]:
88
+ nonlocal data
89
+ replacer_dicc: dict[str, str] = {}
90
+
91
+ for col in self._select.all_clauses:
92
+ if hasattr(col, "_alias_aggregate") or col.alias_clause is None or isinstance(col, Alias):
93
+ continue
94
+ replacer_dicc[col.alias_clause] = col.column
95
+
96
+ cleaned_column_names = [replacer_dicc.get(col, col) for col in self._columns]
97
+
98
+ result = []
99
+ for attr in data:
100
+ dicc_attr = dict(zip(cleaned_column_names, attr))
101
+ result.append(self._flavour(**dicc_attr, **kwargs))
102
+
103
+ return result
104
+
105
+ selector: dict[Type[object], Any] = {
106
+ dict: _dict,
107
+ tuple: _tuple,
108
+ set: _set,
109
+ list: _list,
110
+ }
111
+ return selector.get(self._flavour, _default)(**kwargs)
112
+
113
+ def _clean_response(self) -> TFlavour:
114
+ new_response: list[tuple] = []
115
+ for row in self._response_values:
116
+ new_row: list = []
117
+ for i, data in enumerate(row):
118
+ alias = self._columns[i]
119
+ clause_info = self._select[alias]
120
+ parse_data = self._caster.for_value(data, value_type=clause_info.dtype).from_database
121
+ new_row.append(parse_data)
122
+ new_row = tuple(new_row)
123
+ if not isinstance(new_row, tuple):
124
+ new_row = tuple(new_row)
125
+
126
+ new_response.append(new_row)
127
+ return new_response
128
+
129
+ @staticmethod
130
+ def _is_parser_required[T: Table](clause_info: ClauseInfo[T]) -> bool:
131
+ if clause_info is None:
132
+ return False
133
+
134
+ return clause_info.dtype is shp.Point
@@ -1,3 +1,4 @@
1
1
  from .interface import IAggregate # noqa: F401
2
- from .clause_info import ClauseInfo, AggregateFunctionBase # noqa: F401
2
+ from .clause_info import ClauseInfo # noqa: F401
3
+ from .aggregate_function_base import AggregateFunctionBase # noqa: F401
3
4
  from .clause_info_context import ClauseContextType, ClauseInfoContext # noqa: F401
@@ -0,0 +1,96 @@
1
+ from __future__ import annotations
2
+ import abc
3
+ import typing as tp
4
+
5
+ from ormlambda import Table
6
+ from ormlambda import Column
7
+ from ormlambda.sql.types import (
8
+ TableType,
9
+ ColumnType,
10
+ AliasType,
11
+ )
12
+ from .interface import IAggregate
13
+ from ormlambda.common.errors import NotKeysInIAggregateError
14
+ from ormlambda.sql import ForeignKey
15
+ from ormlambda.sql.table import TableMeta
16
+ from .clause_info import ClauseInfo
17
+ from .clause_info_context import ClauseContextType
18
+
19
+ if tp.TYPE_CHECKING:
20
+ from ormlambda.dialects import Dialect
21
+
22
+
23
+ class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
24
+ def __init__[TProp: Column](
25
+ self,
26
+ table: TableType[T],
27
+ column: tp.Optional[ColumnType[TProp]] = None,
28
+ alias_table: tp.Optional[AliasType[ClauseInfo[T]]] = None,
29
+ alias_clause: tp.Optional[AliasType[ClauseInfo[T]]] = None,
30
+ context: ClauseContextType = None,
31
+ keep_asterisk: bool = False,
32
+ preserve_context: bool = False,
33
+ dtype: TProp = None,
34
+ *,
35
+ dialect: Dialect,
36
+ **kw,
37
+ ):
38
+ self._alias_aggregate = alias_clause
39
+ super().__init__(
40
+ table=table,
41
+ column=column,
42
+ alias_table=alias_table,
43
+ context=context,
44
+ keep_asterisk=keep_asterisk,
45
+ preserve_context=preserve_context,
46
+ dtype=dtype,
47
+ dialect=dialect,
48
+ **kw,
49
+ )
50
+
51
+ @staticmethod
52
+ @abc.abstractmethod
53
+ def FUNCTION_NAME() -> str: ...
54
+
55
+ @classmethod
56
+ def _convert_into_clauseInfo[TypeColumns, TProp](cls, columns: ClauseInfo | ColumnType[TProp], context: ClauseContextType, dialect: Dialect) -> list[ClauseInfo]:
57
+ type DEFAULT = tp.Literal["default"]
58
+ type ClusterType = ColumnType | ForeignKey | DEFAULT
59
+
60
+ dicc_type: dict[ClusterType, tp.Callable[[ClusterType], ClauseInfo]] = {
61
+ Column: lambda column: ClauseInfo(column.table, column, context=context, dialect=dialect),
62
+ ClauseInfo: lambda column: column,
63
+ ForeignKey: lambda tbl: ClauseInfo(tbl.tright, tbl.tright, context=context, dialect=dialect),
64
+ TableMeta: lambda tbl: ClauseInfo(tbl, tbl, context=context, dialect=dialect),
65
+ "default": lambda column: ClauseInfo(table=None, column=column, context=context, dialect=dialect),
66
+ }
67
+ all_clauses: list[ClauseInfo] = []
68
+ if isinstance(columns, str) or not isinstance(columns, tp.Iterable):
69
+ columns = (columns,)
70
+ for value in columns:
71
+ all_clauses.append(dicc_type.get(type(value), dicc_type["default"])(value))
72
+
73
+ return all_clauses
74
+
75
+ @tp.override
76
+ def query(self, dialect: Dialect, **kwargs) -> str:
77
+ wrapped_ci = self.wrapped_clause_info(self)
78
+ if not self._alias_aggregate:
79
+ return wrapped_ci
80
+
81
+ return ClauseInfo(
82
+ table=None,
83
+ column=wrapped_ci,
84
+ alias_clause=self._alias_aggregate,
85
+ context=self._context,
86
+ keep_asterisk=self._keep_asterisk,
87
+ preserve_context=self._preserve_context,
88
+ dialect=self._dialect,
89
+ ).query(dialect, **kwargs)
90
+
91
+ def wrapped_clause_info(self, ci: ClauseInfo[T]) -> str:
92
+ # avoid use placeholder when using IAggregate because no make sense.
93
+ if self._alias_aggregate and (found := self._keyRegex.findall(self._alias_aggregate)):
94
+ raise NotKeysInIAggregateError(found)
95
+
96
+ return f"{self.FUNCTION_NAME()}({ci._create_query(self._dialect)})"
@@ -1,26 +1,24 @@
1
1
  from __future__ import annotations
2
- import abc
3
2
  import typing as tp
4
3
  import re
5
4
 
6
5
  from ormlambda import Table
7
6
  from ormlambda import Column
8
- from ormlambda.common.interfaces.IQueryCommand import IQuery
9
7
  from ormlambda.sql.types import (
10
8
  ASTERISK,
11
9
  TableType,
12
10
  ColumnType,
13
11
  AliasType,
14
12
  )
15
- from .interface import IAggregate
16
- from ormlambda.common.errors import NotKeysInIAggregateError
13
+ from .interface import IClauseInfo
17
14
  from ormlambda.sql import ForeignKey
18
- from ormlambda.sql.table import TableMeta
19
- from ormlambda.caster import Caster
20
15
 
21
16
 
22
17
  from .clause_info_context import ClauseInfoContext, ClauseContextType
23
18
 
19
+ if tp.TYPE_CHECKING:
20
+ from ormlambda.dialects import Dialect
21
+
24
22
 
25
23
  class ReplacePlaceholderError(ValueError):
26
24
  def __init__(self, placeholder: str, attribute: str, *args):
@@ -32,30 +30,6 @@ class ReplacePlaceholderError(ValueError):
32
30
  return "You cannot use {" + self.placeholder + "} placeholder without using '" + self.attr + "' attribute"
33
31
 
34
32
 
35
- class IClauseInfo[T: Table](IQuery):
36
- @property
37
- @abc.abstractmethod
38
- def table(self) -> TableType[T]: ...
39
- @property
40
- @abc.abstractmethod
41
- def alias_clause(self) -> tp.Optional[str]: ...
42
- @property
43
- @abc.abstractmethod
44
- def alias_table(self) -> tp.Optional[str]: ...
45
- @property
46
- @abc.abstractmethod
47
- def column(self) -> str: ...
48
- @property
49
- @abc.abstractmethod
50
- def unresolved_column(self) -> ColumnType: ...
51
- @property
52
- @abc.abstractmethod
53
- def context(self) -> ClauseContextType: ...
54
- @property
55
- @abc.abstractmethod
56
- def dtype[TProp](self) -> tp.Optional[tp.Type[TProp]]: ...
57
-
58
-
59
33
  class ClauseInfo[T: Table](IClauseInfo[T]):
60
34
  _keyRegex: re.Pattern = re.compile(r"{([^{}:]+)}")
61
35
 
@@ -73,6 +47,11 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
73
47
  def __init__(self, table: TableType[T], keep_asterisk: tp.Optional[bool] = ...): ...
74
48
  @tp.overload
75
49
  def __init__(self, table: TableType[T], preserve_context: tp.Optional[bool] = ...): ...
50
+ @tp.overload
51
+ def __init__[TProp](self, table: TableType[T], dtype: tp.Optional[TProp] = ...): ...
52
+
53
+ @tp.overload
54
+ def __init__(self, dialect: Dialect, *args, **kwargs): ...
76
55
 
77
56
  def __init__[TProp](
78
57
  self,
@@ -83,6 +62,10 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
83
62
  context: ClauseContextType = None,
84
63
  keep_asterisk: bool = False,
85
64
  preserve_context: bool = False,
65
+ dtype: tp.Optional[TProp] = None,
66
+ *,
67
+ dialect: Dialect,
68
+ **kw,
86
69
  ):
87
70
  if not self.is_table(table):
88
71
  column = table if not column else column
@@ -95,6 +78,9 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
95
78
  self._context: ClauseContextType = context if context else ClauseInfoContext()
96
79
  self._keep_asterisk: bool = keep_asterisk
97
80
  self._preserve_context: bool = preserve_context
81
+ self._dtype = dtype
82
+
83
+ self._dialect: Dialect = dialect
98
84
 
99
85
  self._placeholderValues: dict[str, tp.Callable[[TProp], str]] = {
100
86
  "column": self.replace_column_placeholder,
@@ -104,8 +90,10 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
104
90
  if not self._preserve_context and (self._context and any([alias_table, alias_clause])):
105
91
  self._context.add_clause_to_context(self)
106
92
 
93
+ super().__init__(**kw)
94
+
107
95
  def __repr__(self) -> str:
108
- return f"{type(self).__name__}: query -> {self.query}"
96
+ return f"{type(self).__name__}: query -> {self.query(self._dialect)}"
109
97
 
110
98
  def replace_column_placeholder[TProp](self, column: ColumnType[TProp]) -> str:
111
99
  if not column:
@@ -168,6 +156,9 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
168
156
 
169
157
  @property
170
158
  def dtype[TProp](self) -> tp.Optional[tp.Type[TProp]]:
159
+ if self._dtype is not None:
160
+ return self._dtype
161
+
171
162
  if isinstance(self._column, Column):
172
163
  return self._column.dtype
173
164
 
@@ -175,11 +166,10 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
175
166
  return self._column
176
167
  return type(self._column)
177
168
 
178
- @property
179
- def query(self) -> str:
180
- return self._create_query()
169
+ def query(self, dialect: Dialect, **kwargs) -> str:
170
+ return self._create_query(dialect, **kwargs)
181
171
 
182
- def _create_query(self) -> str:
172
+ def _create_query(self, dialect: Dialect, **kwargs) -> str:
183
173
  # when passing some value that is not a column name
184
174
  if not self.table and not self._alias_clause:
185
175
  return self.column
@@ -201,10 +191,9 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
201
191
  return self._join_table_and_column(self._column)
202
192
 
203
193
  def _join_table_and_column[TProp](self, column: ColumnType[TProp]) -> str:
204
- # FIXME [ ]: Study how to deacoplate from mysql database
205
- from ormlambda.databases.my_sql.repository import MySQLRepository
194
+ # FIXME [x]: Study how to deacoplate from mysql database
206
195
 
207
- caster = Caster(MySQLRepository)
196
+ caster = self._dialect.caster()
208
197
 
209
198
  if self.alias_table:
210
199
  table = self._wrapped_with_quotes(self.alias_table)
@@ -241,22 +230,20 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
241
230
  alias_clause=self._alias_clause,
242
231
  context=self._context,
243
232
  keep_asterisk=self._keep_asterisk,
233
+ dialect=self._dialect,
244
234
  )
245
235
 
246
236
  if self._alias_table and self._alias_clause: # We'll add an "*" when we are certain that we have included 'alias_clause' attr
247
237
  return self._join_table_and_column(ASTERISK)
248
238
 
249
- columns: list[ClauseInfo] = [ClauseCreator(column).query for column in self.table.get_columns()]
239
+ columns: list[ClauseInfo] = [ClauseCreator(column).query(self._dialect) for column in self.table.get_columns()]
250
240
 
251
241
  return ", ".join(columns)
252
242
 
253
- # FIXME [ ]: Study how to deacoplate from mysql database
243
+ # FIXME [x]: Study how to deacoplate from mysql database
254
244
  def _column_resolver[TProp](self, column: ColumnType[TProp]) -> str:
255
- from ormlambda.databases.my_sql.repository import MySQLRepository
256
-
257
- caster = Caster(MySQLRepository)
258
245
  if isinstance(column, ClauseInfo):
259
- return column.query
246
+ return column.query(self._dialect)
260
247
 
261
248
  if isinstance(column, tp.Iterable) and isinstance(column[0], ClauseInfo):
262
249
  return self.join_clauses(column)
@@ -277,6 +264,7 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
277
264
  if self.is_foreign_key(self._column):
278
265
  return self._column.tright.__table_name__
279
266
 
267
+ caster = self._dialect.caster()
280
268
  casted_value = caster.for_value(column, self.dtype)
281
269
  if not self._table:
282
270
  # if we haven't some table atrribute, we assume that the user want to retrieve the string_data from caster.
@@ -320,12 +308,13 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
320
308
  return self._context.get_table_alias(self.table)
321
309
 
322
310
  @staticmethod
323
- def join_clauses(clauses: list[ClauseInfo[T]], chr: str = ",", context: tp.Optional[ClauseInfoContext] = None) -> str:
311
+ def join_clauses(clauses: list[ClauseInfo[T]], chr: str = ",", context: tp.Optional[ClauseInfoContext] = None, *, dialect: Dialect) -> str:
324
312
  queries: list[str] = []
325
313
  for c in clauses:
326
314
  if context:
327
315
  c.context = context
328
- queries.append(c.query)
316
+ c._dialect = dialect
317
+ queries.append(c.query(dialect))
329
318
 
330
319
  return f"{chr} ".join(queries)
331
320
 
@@ -363,72 +352,3 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
363
352
  if isinstance(data, Column):
364
353
  return True
365
354
  return False
366
-
367
-
368
- class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
369
- def __init__[TProp: Column](
370
- self,
371
- table: TableType[T],
372
- column: tp.Optional[ColumnType[TProp]] = None,
373
- alias_table: tp.Optional[AliasType[ClauseInfo[T]]] = None,
374
- alias_clause: tp.Optional[AliasType[ClauseInfo[T]]] = None,
375
- context: ClauseContextType = None,
376
- keep_asterisk: bool = False,
377
- preserve_context: bool = False,
378
- ):
379
- self._alias_aggregate = alias_clause
380
- super().__init__(
381
- table=table,
382
- column=column,
383
- alias_table=alias_table,
384
- context=context,
385
- keep_asterisk=keep_asterisk,
386
- preserve_context=preserve_context,
387
- )
388
-
389
- @staticmethod
390
- @abc.abstractmethod
391
- def FUNCTION_NAME() -> str: ...
392
-
393
- @classmethod
394
- def _convert_into_clauseInfo[TypeColumns, TProp](cls, columns: ClauseInfo | ColumnType[TProp], context: ClauseContextType) -> list[ClauseInfo]:
395
- type DEFAULT = tp.Literal["default"]
396
- type ClusterType = ColumnType | ForeignKey | DEFAULT
397
-
398
- dicc_type: dict[ClusterType, tp.Callable[[ClusterType], ClauseInfo]] = {
399
- Column: lambda column: ClauseInfo(column.table, column, context=context),
400
- ClauseInfo: lambda column: column,
401
- ForeignKey: lambda tbl: ClauseInfo(tbl.tright, tbl.tright, context=context),
402
- TableMeta: lambda tbl: ClauseInfo(tbl, tbl, context=context),
403
- "default": lambda column: ClauseInfo(table=None, column=column, context=context),
404
- }
405
- all_clauses: list[ClauseInfo] = []
406
- if isinstance(columns, str) or not isinstance(columns, tp.Iterable):
407
- columns = (columns,)
408
- for value in columns:
409
- all_clauses.append(dicc_type.get(type(value), dicc_type["default"])(value))
410
-
411
- return all_clauses
412
-
413
- @tp.override
414
- @property
415
- def query(self) -> str:
416
- wrapped_ci = self.wrapped_clause_info(self)
417
- if not self._alias_aggregate:
418
- return wrapped_ci
419
-
420
- return ClauseInfo(
421
- table=None,
422
- column=wrapped_ci,
423
- alias_clause=self._alias_aggregate,
424
- context=self._context,
425
- keep_asterisk=self._keep_asterisk,
426
- preserve_context=self._preserve_context,
427
- ).query
428
-
429
- def wrapped_clause_info(self, ci: ClauseInfo[T]) -> str:
430
- # avoid use placeholder when using IAggregate because no make sense.
431
- if self._alias_aggregate and (found := self._keyRegex.findall(self._alias_aggregate)):
432
- raise NotKeysInIAggregateError(found)
433
-
434
- return f"{self.FUNCTION_NAME()}({ci._create_query()})"
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+ import abc
3
+ import typing as tp
4
+
5
+ from ormlambda import Table
6
+ from ormlambda.common.interfaces.IQueryCommand import IQuery
7
+ from ormlambda.sql.types import (
8
+ TableType,
9
+ ColumnType,
10
+ )
11
+
12
+
13
+ from ..clause_info_context import ClauseContextType
14
+
15
+
16
+ class IClauseInfo[T: Table](IQuery):
17
+ @property
18
+ @abc.abstractmethod
19
+ def table(self) -> TableType[T]: ...
20
+ @property
21
+ @abc.abstractmethod
22
+ def alias_clause(self) -> tp.Optional[str]: ...
23
+ @property
24
+ @abc.abstractmethod
25
+ def alias_table(self) -> tp.Optional[str]: ...
26
+ @property
27
+ @abc.abstractmethod
28
+ def column(self) -> str: ...
29
+ @property
30
+ @abc.abstractmethod
31
+ def unresolved_column(self) -> ColumnType: ...
32
+ @property
33
+ @abc.abstractmethod
34
+ def context(self) -> ClauseContextType: ...
35
+ @property
36
+ @abc.abstractmethod
37
+ def dtype[TProp](self) -> tp.Optional[tp.Type[TProp]]: ...
@@ -1 +1,2 @@
1
1
  from .IAggregate import IAggregate # noqa: F401
2
+ from .IClauseInfo import IClauseInfo # noqa: F401
@@ -0,0 +1,14 @@
1
+ from .alias import Alias # noqa: F401
2
+ from .count import Count # noqa: F401
3
+ from .delete import Delete # noqa: F401
4
+ from .group_by import GroupBy # noqa: F401
5
+ from .insert import Insert # noqa: F401
6
+ from .joins import JoinSelector # noqa: F401
7
+ from .limit import Limit # noqa: F401
8
+ from .offset import Offset # noqa: F401
9
+ from .order import Order # noqa: F401
10
+ from .select import Select # noqa: F401
11
+ from .where import Where # noqa: F401
12
+ from .having import Having # noqa: F401
13
+ from .update import Update # noqa: F401
14
+ from .upsert import Upsert # noqa: F401
@@ -1,18 +1,21 @@
1
1
  from __future__ import annotations
2
2
  import typing as tp
3
3
 
4
- from ormlambda import Table
5
4
  from ormlambda.sql.clause_info import ClauseInfo
6
- from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
7
- from ormlambda.sql.types import TableType
5
+ from ormlambda.sql.elements import ClauseElement
6
+
8
7
 
9
8
  if tp.TYPE_CHECKING:
10
- from ormlambda.sql.types import ColumnType
11
9
  from ormlambda import Table
10
+ from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
11
+ from ormlambda.sql.types import TableType
12
+ from ormlambda.sql.types import ColumnType
12
13
  from ormlambda.sql.types import AliasType
13
14
 
14
15
 
15
- class Alias[T: Table](ClauseInfo[T]):
16
+ class Alias[T: Table](ClauseInfo[T], ClauseElement):
17
+ __visit_name__ = "alias"
18
+
16
19
  def __init__[TProp](
17
20
  self,
18
21
  table: TableType[T],
@@ -22,7 +25,21 @@ class Alias[T: Table](ClauseInfo[T]):
22
25
  context: ClauseContextType = None,
23
26
  keep_asterisk: bool = False,
24
27
  preserve_context: bool = False,
28
+ **kw,
25
29
  ):
26
30
  if not alias_clause:
27
31
  raise TypeError
28
- super().__init__(table, column, alias_table, alias_clause, context, keep_asterisk, preserve_context)
32
+ super().__init__(
33
+ table,
34
+ column,
35
+ alias_table=alias_table,
36
+ alias_clause=alias_clause,
37
+ context=context,
38
+ keep_asterisk=keep_asterisk,
39
+ preserve_context=preserve_context,
40
+ dtype=None,
41
+ **kw,
42
+ )
43
+
44
+
45
+ __all__ = ["Alias"]
@@ -9,13 +9,18 @@ from ormlambda import Table
9
9
  import typing as tp
10
10
 
11
11
  from ormlambda.sql.types import ASTERISK
12
+ from ormlambda.sql.elements import ClauseElement
13
+
12
14
 
13
15
  if tp.TYPE_CHECKING:
14
16
  from ormlambda import Table
15
17
  from ormlambda.sql.types import ColumnType, AliasType, TableType
18
+ from ormlambda.dialects import Dialect
19
+
16
20
 
21
+ class Count[T: Table](AggregateFunctionBase[T], ClauseElement):
22
+ __visit_name__ = "count"
17
23
 
18
- class Count[T: Table](AggregateFunctionBase[T]):
19
24
  @staticmethod
20
25
  def FUNCTION_NAME() -> str:
21
26
  return "COUNT"
@@ -28,6 +33,9 @@ class Count[T: Table](AggregateFunctionBase[T]):
28
33
  context: ClauseContextType = None,
29
34
  keep_asterisk: bool = True,
30
35
  preserve_context: bool = True,
36
+ *,
37
+ dialect: Dialect,
38
+ **kw,
31
39
  ) -> None:
32
40
  table = self.extract_table(element)
33
41
  column = element if self.is_column(element) else ASTERISK
@@ -40,4 +48,10 @@ class Count[T: Table](AggregateFunctionBase[T]):
40
48
  context=context,
41
49
  keep_asterisk=keep_asterisk,
42
50
  preserve_context=preserve_context,
51
+ dtype=int,
52
+ dialect=dialect,
53
+ **kw,
43
54
  )
55
+
56
+
57
+ __all__ = ["Count"]