ormlambda 3.12.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 (150) hide show
  1. ormlambda/__init__.py +2 -0
  2. ormlambda/caster/__init__.py +1 -1
  3. ormlambda/caster/caster.py +29 -12
  4. ormlambda/common/abstract_classes/clause_info_converter.py +4 -12
  5. ormlambda/common/abstract_classes/decomposition_query.py +17 -2
  6. ormlambda/common/abstract_classes/non_query_base.py +9 -7
  7. ormlambda/common/abstract_classes/query_base.py +3 -1
  8. ormlambda/common/errors/__init__.py +29 -0
  9. ormlambda/common/interfaces/IQueryCommand.py +6 -2
  10. ormlambda/dialects/__init__.py +39 -0
  11. ormlambda/dialects/default/__init__.py +1 -0
  12. ormlambda/dialects/default/base.py +39 -0
  13. ormlambda/dialects/interface/__init__.py +1 -0
  14. ormlambda/dialects/interface/dialect.py +78 -0
  15. ormlambda/dialects/mysql/__init__.py +38 -0
  16. ormlambda/dialects/mysql/base.py +388 -0
  17. ormlambda/dialects/mysql/caster/caster.py +39 -0
  18. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/__init__.py +1 -0
  19. ormlambda/dialects/mysql/caster/types/boolean.py +35 -0
  20. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/bytes.py +7 -7
  21. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/datetime.py +7 -7
  22. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/float.py +7 -7
  23. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/int.py +7 -7
  24. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/iterable.py +7 -7
  25. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/none.py +8 -7
  26. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/point.py +4 -4
  27. ormlambda/{databases/my_sql → dialects/mysql}/caster/types/string.py +7 -7
  28. ormlambda/{databases/my_sql → dialects/mysql}/clauses/ST_AsText.py +8 -7
  29. ormlambda/{databases/my_sql → dialects/mysql}/clauses/ST_Contains.py +10 -5
  30. ormlambda/dialects/mysql/clauses/__init__.py +13 -0
  31. ormlambda/dialects/mysql/clauses/count.py +33 -0
  32. ormlambda/dialects/mysql/clauses/delete.py +9 -0
  33. ormlambda/dialects/mysql/clauses/group_by.py +17 -0
  34. ormlambda/dialects/mysql/clauses/having.py +12 -0
  35. ormlambda/dialects/mysql/clauses/insert.py +9 -0
  36. ormlambda/dialects/mysql/clauses/joins.py +14 -0
  37. ormlambda/dialects/mysql/clauses/limit.py +6 -0
  38. ormlambda/dialects/mysql/clauses/offset.py +6 -0
  39. ormlambda/dialects/mysql/clauses/order.py +8 -0
  40. ormlambda/dialects/mysql/clauses/update.py +8 -0
  41. ormlambda/dialects/mysql/clauses/upsert.py +9 -0
  42. ormlambda/dialects/mysql/clauses/where.py +7 -0
  43. ormlambda/dialects/mysql/mysqlconnector.py +46 -0
  44. ormlambda/dialects/mysql/repository/__init__.py +1 -0
  45. ormlambda/dialects/mysql/repository/repository.py +212 -0
  46. ormlambda/dialects/mysql/types.py +732 -0
  47. ormlambda/dialects/sqlite/__init__.py +5 -0
  48. ormlambda/dialects/sqlite/base.py +47 -0
  49. ormlambda/dialects/sqlite/pysqlite.py +32 -0
  50. ormlambda/engine/__init__.py +1 -0
  51. ormlambda/engine/base.py +77 -0
  52. ormlambda/engine/create.py +9 -23
  53. ormlambda/engine/url.py +31 -19
  54. ormlambda/env.py +30 -0
  55. ormlambda/errors.py +17 -0
  56. ormlambda/model/base_model.py +7 -9
  57. ormlambda/repository/base_repository.py +36 -5
  58. ormlambda/repository/interfaces/IRepositoryBase.py +119 -12
  59. ormlambda/repository/response.py +134 -0
  60. ormlambda/sql/clause_info/aggregate_function_base.py +19 -9
  61. ormlambda/sql/clause_info/clause_info.py +34 -17
  62. ormlambda/sql/clauses/__init__.py +14 -0
  63. ormlambda/{databases/my_sql → sql}/clauses/alias.py +23 -6
  64. ormlambda/{databases/my_sql → sql}/clauses/count.py +15 -1
  65. ormlambda/{databases/my_sql → sql}/clauses/delete.py +22 -7
  66. ormlambda/sql/clauses/group_by.py +30 -0
  67. ormlambda/{databases/my_sql → sql}/clauses/having.py +7 -2
  68. ormlambda/{databases/my_sql → sql}/clauses/insert.py +16 -9
  69. ormlambda/sql/clauses/interfaces/__init__.py +5 -0
  70. ormlambda/{components → sql/clauses}/join/join_context.py +15 -7
  71. ormlambda/{databases/my_sql → sql}/clauses/joins.py +29 -19
  72. ormlambda/sql/clauses/limit.py +15 -0
  73. ormlambda/sql/clauses/offset.py +15 -0
  74. ormlambda/{databases/my_sql → sql}/clauses/order.py +14 -24
  75. ormlambda/{databases/my_sql → sql}/clauses/select.py +12 -13
  76. ormlambda/{databases/my_sql → sql}/clauses/update.py +24 -11
  77. ormlambda/{databases/my_sql → sql}/clauses/upsert.py +17 -12
  78. ormlambda/{databases/my_sql → sql}/clauses/where.py +28 -8
  79. ormlambda/sql/column/__init__.py +1 -0
  80. ormlambda/sql/{column.py → column/column.py} +82 -22
  81. ormlambda/sql/comparer.py +51 -37
  82. ormlambda/sql/compiler.py +668 -0
  83. ormlambda/sql/ddl.py +82 -0
  84. ormlambda/sql/elements.py +36 -0
  85. ormlambda/sql/foreign_key.py +61 -39
  86. ormlambda/{databases/my_sql → sql}/functions/concat.py +13 -5
  87. ormlambda/{databases/my_sql → sql}/functions/max.py +9 -4
  88. ormlambda/{databases/my_sql → sql}/functions/min.py +9 -13
  89. ormlambda/{databases/my_sql → sql}/functions/sum.py +8 -10
  90. ormlambda/sql/sqltypes.py +647 -0
  91. ormlambda/sql/table/__init__.py +1 -1
  92. ormlambda/sql/table/table.py +175 -0
  93. ormlambda/sql/table/table_constructor.py +1 -208
  94. ormlambda/sql/type_api.py +35 -0
  95. ormlambda/sql/types.py +3 -1
  96. ormlambda/sql/visitors.py +74 -0
  97. ormlambda/statements/__init__.py +1 -0
  98. ormlambda/statements/base_statement.py +28 -38
  99. ormlambda/statements/interfaces/IStatements.py +8 -4
  100. ormlambda/{databases/my_sql → statements}/query_builder.py +35 -30
  101. ormlambda/{databases/my_sql → statements}/statements.py +57 -61
  102. ormlambda/statements/types.py +2 -2
  103. ormlambda/types/__init__.py +24 -0
  104. ormlambda/types/metadata.py +42 -0
  105. ormlambda/util/__init__.py +87 -0
  106. ormlambda/{utils → util}/module_tree/dynamic_module.py +1 -1
  107. ormlambda/util/plugin_loader.py +32 -0
  108. ormlambda/util/typing.py +6 -0
  109. ormlambda-3.34.0.dist-info/AUTHORS +32 -0
  110. {ormlambda-3.12.2.dist-info → ormlambda-3.34.0.dist-info}/METADATA +1 -1
  111. ormlambda-3.34.0.dist-info/RECORD +152 -0
  112. ormlambda/components/__init__.py +0 -4
  113. ormlambda/components/delete/__init__.py +0 -2
  114. ormlambda/components/delete/abstract_delete.py +0 -17
  115. ormlambda/components/insert/__init__.py +0 -2
  116. ormlambda/components/insert/abstract_insert.py +0 -25
  117. ormlambda/components/select/__init__.py +0 -1
  118. ormlambda/components/update/__init__.py +0 -2
  119. ormlambda/components/update/abstract_update.py +0 -29
  120. ormlambda/components/upsert/__init__.py +0 -2
  121. ormlambda/components/upsert/abstract_upsert.py +0 -25
  122. ormlambda/databases/__init__.py +0 -5
  123. ormlambda/databases/my_sql/__init__.py +0 -4
  124. ormlambda/databases/my_sql/caster/caster.py +0 -39
  125. ormlambda/databases/my_sql/clauses/__init__.py +0 -20
  126. ormlambda/databases/my_sql/clauses/create_database.py +0 -35
  127. ormlambda/databases/my_sql/clauses/drop_database.py +0 -17
  128. ormlambda/databases/my_sql/clauses/drop_table.py +0 -26
  129. ormlambda/databases/my_sql/clauses/group_by.py +0 -30
  130. ormlambda/databases/my_sql/clauses/limit.py +0 -17
  131. ormlambda/databases/my_sql/clauses/offset.py +0 -17
  132. ormlambda/databases/my_sql/repository/__init__.py +0 -1
  133. ormlambda/databases/my_sql/repository/repository.py +0 -351
  134. ormlambda/engine/template.py +0 -47
  135. ormlambda/sql/dtypes.py +0 -94
  136. ormlambda/utils/__init__.py +0 -1
  137. ormlambda-3.12.2.dist-info/RECORD +0 -125
  138. /ormlambda/{databases/my_sql → dialects/mysql}/caster/__init__.py +0 -0
  139. /ormlambda/{databases/my_sql/types.py → dialects/mysql/repository/pool_types.py} +0 -0
  140. /ormlambda/{components/delete → sql/clauses/interfaces}/IDelete.py +0 -0
  141. /ormlambda/{components/insert → sql/clauses/interfaces}/IInsert.py +0 -0
  142. /ormlambda/{components/select → sql/clauses/interfaces}/ISelect.py +0 -0
  143. /ormlambda/{components/update → sql/clauses/interfaces}/IUpdate.py +0 -0
  144. /ormlambda/{components/upsert → sql/clauses/interfaces}/IUpsert.py +0 -0
  145. /ormlambda/{components → sql/clauses}/join/__init__.py +0 -0
  146. /ormlambda/{databases/my_sql → sql}/functions/__init__.py +0 -0
  147. /ormlambda/{utils → util}/module_tree/__init__.py +0 -0
  148. /ormlambda/{utils → util}/module_tree/dfs_traversal.py +0 -0
  149. {ormlambda-3.12.2.dist-info → ormlambda-3.34.0.dist-info}/LICENSE +0 -0
  150. {ormlambda-3.12.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
@@ -16,6 +16,9 @@ from ormlambda.sql.table import TableMeta
16
16
  from .clause_info import ClauseInfo
17
17
  from .clause_info_context import ClauseContextType
18
18
 
19
+ if tp.TYPE_CHECKING:
20
+ from ormlambda.dialects import Dialect
21
+
19
22
 
20
23
  class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
21
24
  def __init__[TProp: Column](
@@ -27,6 +30,10 @@ class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
27
30
  context: ClauseContextType = None,
28
31
  keep_asterisk: bool = False,
29
32
  preserve_context: bool = False,
33
+ dtype: TProp = None,
34
+ *,
35
+ dialect: Dialect,
36
+ **kw,
30
37
  ):
31
38
  self._alias_aggregate = alias_clause
32
39
  super().__init__(
@@ -36,6 +43,9 @@ class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
36
43
  context=context,
37
44
  keep_asterisk=keep_asterisk,
38
45
  preserve_context=preserve_context,
46
+ dtype=dtype,
47
+ dialect=dialect,
48
+ **kw,
39
49
  )
40
50
 
41
51
  @staticmethod
@@ -43,16 +53,16 @@ class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
43
53
  def FUNCTION_NAME() -> str: ...
44
54
 
45
55
  @classmethod
46
- def _convert_into_clauseInfo[TypeColumns, TProp](cls, columns: ClauseInfo | ColumnType[TProp], context: ClauseContextType) -> list[ClauseInfo]:
56
+ def _convert_into_clauseInfo[TypeColumns, TProp](cls, columns: ClauseInfo | ColumnType[TProp], context: ClauseContextType, dialect: Dialect) -> list[ClauseInfo]:
47
57
  type DEFAULT = tp.Literal["default"]
48
58
  type ClusterType = ColumnType | ForeignKey | DEFAULT
49
59
 
50
60
  dicc_type: dict[ClusterType, tp.Callable[[ClusterType], ClauseInfo]] = {
51
- Column: lambda column: ClauseInfo(column.table, column, context=context),
61
+ Column: lambda column: ClauseInfo(column.table, column, context=context, dialect=dialect),
52
62
  ClauseInfo: lambda column: column,
53
- ForeignKey: lambda tbl: ClauseInfo(tbl.tright, tbl.tright, context=context),
54
- TableMeta: lambda tbl: ClauseInfo(tbl, tbl, context=context),
55
- "default": lambda column: ClauseInfo(table=None, column=column, context=context),
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),
56
66
  }
57
67
  all_clauses: list[ClauseInfo] = []
58
68
  if isinstance(columns, str) or not isinstance(columns, tp.Iterable):
@@ -63,8 +73,7 @@ class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
63
73
  return all_clauses
64
74
 
65
75
  @tp.override
66
- @property
67
- def query(self) -> str:
76
+ def query(self, dialect: Dialect, **kwargs) -> str:
68
77
  wrapped_ci = self.wrapped_clause_info(self)
69
78
  if not self._alias_aggregate:
70
79
  return wrapped_ci
@@ -76,11 +85,12 @@ class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
76
85
  context=self._context,
77
86
  keep_asterisk=self._keep_asterisk,
78
87
  preserve_context=self._preserve_context,
79
- ).query
88
+ dialect=self._dialect,
89
+ ).query(dialect, **kwargs)
80
90
 
81
91
  def wrapped_clause_info(self, ci: ClauseInfo[T]) -> str:
82
92
  # avoid use placeholder when using IAggregate because no make sense.
83
93
  if self._alias_aggregate and (found := self._keyRegex.findall(self._alias_aggregate)):
84
94
  raise NotKeysInIAggregateError(found)
85
95
 
86
- return f"{self.FUNCTION_NAME()}({ci._create_query()})"
96
+ return f"{self.FUNCTION_NAME()}({ci._create_query(self._dialect)})"
@@ -12,11 +12,13 @@ from ormlambda.sql.types import (
12
12
  )
13
13
  from .interface import IClauseInfo
14
14
  from ormlambda.sql import ForeignKey
15
- from ormlambda.caster import Caster
16
15
 
17
16
 
18
17
  from .clause_info_context import ClauseInfoContext, ClauseContextType
19
18
 
19
+ if tp.TYPE_CHECKING:
20
+ from ormlambda.dialects import Dialect
21
+
20
22
 
21
23
  class ReplacePlaceholderError(ValueError):
22
24
  def __init__(self, placeholder: str, attribute: str, *args):
@@ -45,6 +47,11 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
45
47
  def __init__(self, table: TableType[T], keep_asterisk: tp.Optional[bool] = ...): ...
46
48
  @tp.overload
47
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): ...
48
55
 
49
56
  def __init__[TProp](
50
57
  self,
@@ -55,6 +62,10 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
55
62
  context: ClauseContextType = None,
56
63
  keep_asterisk: bool = False,
57
64
  preserve_context: bool = False,
65
+ dtype: tp.Optional[TProp] = None,
66
+ *,
67
+ dialect: Dialect,
68
+ **kw,
58
69
  ):
59
70
  if not self.is_table(table):
60
71
  column = table if not column else column
@@ -67,6 +78,9 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
67
78
  self._context: ClauseContextType = context if context else ClauseInfoContext()
68
79
  self._keep_asterisk: bool = keep_asterisk
69
80
  self._preserve_context: bool = preserve_context
81
+ self._dtype = dtype
82
+
83
+ self._dialect: Dialect = dialect
70
84
 
71
85
  self._placeholderValues: dict[str, tp.Callable[[TProp], str]] = {
72
86
  "column": self.replace_column_placeholder,
@@ -76,8 +90,10 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
76
90
  if not self._preserve_context and (self._context and any([alias_table, alias_clause])):
77
91
  self._context.add_clause_to_context(self)
78
92
 
93
+ super().__init__(**kw)
94
+
79
95
  def __repr__(self) -> str:
80
- return f"{type(self).__name__}: query -> {self.query}"
96
+ return f"{type(self).__name__}: query -> {self.query(self._dialect)}"
81
97
 
82
98
  def replace_column_placeholder[TProp](self, column: ColumnType[TProp]) -> str:
83
99
  if not column:
@@ -140,6 +156,9 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
140
156
 
141
157
  @property
142
158
  def dtype[TProp](self) -> tp.Optional[tp.Type[TProp]]:
159
+ if self._dtype is not None:
160
+ return self._dtype
161
+
143
162
  if isinstance(self._column, Column):
144
163
  return self._column.dtype
145
164
 
@@ -147,11 +166,10 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
147
166
  return self._column
148
167
  return type(self._column)
149
168
 
150
- @property
151
- def query(self) -> str:
152
- return self._create_query()
169
+ def query(self, dialect: Dialect, **kwargs) -> str:
170
+ return self._create_query(dialect, **kwargs)
153
171
 
154
- def _create_query(self) -> str:
172
+ def _create_query(self, dialect: Dialect, **kwargs) -> str:
155
173
  # when passing some value that is not a column name
156
174
  if not self.table and not self._alias_clause:
157
175
  return self.column
@@ -173,10 +191,9 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
173
191
  return self._join_table_and_column(self._column)
174
192
 
175
193
  def _join_table_and_column[TProp](self, column: ColumnType[TProp]) -> str:
176
- # FIXME [ ]: Study how to deacoplate from mysql database
177
- from ormlambda.databases.my_sql.repository import MySQLRepository
194
+ # FIXME [x]: Study how to deacoplate from mysql database
178
195
 
179
- caster = Caster(MySQLRepository)
196
+ caster = self._dialect.caster()
180
197
 
181
198
  if self.alias_table:
182
199
  table = self._wrapped_with_quotes(self.alias_table)
@@ -213,22 +230,20 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
213
230
  alias_clause=self._alias_clause,
214
231
  context=self._context,
215
232
  keep_asterisk=self._keep_asterisk,
233
+ dialect=self._dialect,
216
234
  )
217
235
 
218
236
  if self._alias_table and self._alias_clause: # We'll add an "*" when we are certain that we have included 'alias_clause' attr
219
237
  return self._join_table_and_column(ASTERISK)
220
238
 
221
- 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()]
222
240
 
223
241
  return ", ".join(columns)
224
242
 
225
- # FIXME [ ]: Study how to deacoplate from mysql database
243
+ # FIXME [x]: Study how to deacoplate from mysql database
226
244
  def _column_resolver[TProp](self, column: ColumnType[TProp]) -> str:
227
- from ormlambda.databases.my_sql.repository import MySQLRepository
228
-
229
- caster = Caster(MySQLRepository)
230
245
  if isinstance(column, ClauseInfo):
231
- return column.query
246
+ return column.query(self._dialect)
232
247
 
233
248
  if isinstance(column, tp.Iterable) and isinstance(column[0], ClauseInfo):
234
249
  return self.join_clauses(column)
@@ -249,6 +264,7 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
249
264
  if self.is_foreign_key(self._column):
250
265
  return self._column.tright.__table_name__
251
266
 
267
+ caster = self._dialect.caster()
252
268
  casted_value = caster.for_value(column, self.dtype)
253
269
  if not self._table:
254
270
  # if we haven't some table atrribute, we assume that the user want to retrieve the string_data from caster.
@@ -292,12 +308,13 @@ class ClauseInfo[T: Table](IClauseInfo[T]):
292
308
  return self._context.get_table_alias(self.table)
293
309
 
294
310
  @staticmethod
295
- 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:
296
312
  queries: list[str] = []
297
313
  for c in clauses:
298
314
  if context:
299
315
  c.context = context
300
- queries.append(c.query)
316
+ c._dialect = dialect
317
+ queries.append(c.query(dialect))
301
318
 
302
319
  return f"{chr} ".join(queries)
303
320
 
@@ -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"]
@@ -1,16 +1,22 @@
1
+ from __future__ import annotations
1
2
  from typing import Any, Optional, override, Iterable, TYPE_CHECKING
2
3
 
3
4
  if TYPE_CHECKING:
4
5
  from ormlambda import Column
6
+ from ormlambda.engine import Engine
5
7
 
6
8
  from ormlambda import Table
7
- from ormlambda.repository import IRepositoryBase
8
- from ormlambda.components.delete import DeleteQueryBase
9
+ from ormlambda import BaseRepository
10
+ from ormlambda.sql.clauses.interfaces import IDelete
11
+ from ormlambda.common.abstract_classes import NonQueryBase
12
+ from ormlambda.sql.elements import ClauseElement
9
13
 
10
14
 
11
- class DeleteQuery[T: Table](DeleteQueryBase[T, IRepositoryBase]):
12
- def __init__(self, model: T, repository: IRepositoryBase) -> None:
13
- super().__init__(model, repository)
15
+ class Delete[T: Table, TRepo](NonQueryBase[T, TRepo], IDelete[T], ClauseElement):
16
+ __visit_name__ = "delete"
17
+
18
+ def __init__(self, model: T, repository: BaseRepository[TRepo], engine: Engine) -> None:
19
+ super().__init__(model, repository, engine=engine)
14
20
 
15
21
  @property
16
22
  def CLAUSE(self) -> str:
@@ -24,7 +30,13 @@ class DeleteQuery[T: Table](DeleteQueryBase[T, IRepositoryBase]):
24
30
  if pk is None:
25
31
  raise Exception(f"You cannot use 'DELETE' query without set primary key in '{instances.__table_name__}'")
26
32
  col = pk.column_name
27
- value = str(instances[pk])
33
+
34
+ pk_value = instances[pk]
35
+
36
+ if not pk_value:
37
+ raise ValueError(f"primary key value '{pk_value}' must not be empty.")
38
+
39
+ value = str(pk_value)
28
40
 
29
41
  elif isinstance(instances, Iterable):
30
42
  value: list[Any] = []
@@ -53,4 +65,7 @@ class DeleteQuery[T: Table](DeleteQueryBase[T, IRepositoryBase]):
53
65
  def execute(self) -> None:
54
66
  if not self._query:
55
67
  raise ValueError
56
- return self._repository.execute_with_values(self._query, self._values)
68
+ return self._engine.repository.execute_with_values(self._query, self._values)
69
+
70
+
71
+ __all__ = ["Delete"]
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from ormlambda.dialects import Dialect
6
+ from ormlambda.sql.clause_info import AggregateFunctionBase, ClauseInfoContext
7
+ from ormlambda.sql.types import ColumnType
8
+ from ormlambda.sql.elements import ClauseElement
9
+
10
+
11
+ class GroupBy(AggregateFunctionBase, ClauseElement):
12
+ __visit_name__ = "group_by"
13
+
14
+ @classmethod
15
+ def FUNCTION_NAME(self) -> str:
16
+ return "GROUP BY"
17
+
18
+ def __init__(self, column: ColumnType, context: ClauseInfoContext, dialect: Dialect, **kwargs):
19
+ super().__init__(
20
+ table=column.table,
21
+ column=column,
22
+ alias_table=None,
23
+ alias_clause=None,
24
+ context=context,
25
+ dialect=dialect,
26
+ **kwargs,
27
+ )
28
+
29
+
30
+ __all__ = ["GroupBy"]
@@ -8,9 +8,14 @@ class Having(Where):
8
8
  The purpose of this class is to create 'WHERE' condition queries properly.
9
9
  """
10
10
 
11
- def __init__(self, *comparer, restrictive=True, context=None):
12
- super().__init__(*comparer, restrictive=restrictive, context=context)
11
+ __visit_name__ = "having"
12
+
13
+ def __init__(self, *comparer, restrictive=True, context=None, **kw):
14
+ super().__init__(*comparer, restrictive=restrictive, context=context, **kw)
13
15
 
14
16
  @staticmethod
15
17
  def FUNCTION_NAME() -> str:
16
18
  return "HAVING"
19
+
20
+
21
+ __all__ = ["Having"]
@@ -4,17 +4,21 @@ from typing import override, Iterable, TYPE_CHECKING
4
4
 
5
5
  from ormlambda import Table
6
6
  from ormlambda import Column
7
- from ormlambda.components.insert import InsertQueryBase
8
- from ormlambda.repository import IRepositoryBase
9
- from ormlambda.caster import Caster
7
+
8
+ from ormlambda.sql.clauses.interfaces import IInsert
9
+ from ormlambda.common.abstract_classes import NonQueryBase
10
+ from ormlambda.sql.elements import ClauseElement
11
+
10
12
 
11
13
  if TYPE_CHECKING:
12
- from ormlambda.databases.my_sql import MySQLRepository
14
+ from ormlambda.dialects import Dialect
15
+
13
16
 
17
+ class Insert[T: Table, TRepo](NonQueryBase[T, TRepo], IInsert[T], ClauseElement):
18
+ __visit_name__ = "insert"
14
19
 
15
- class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase]):
16
- def __init__(self, model: T, repository: MySQLRepository) -> None:
17
- super().__init__(model, repository)
20
+ def __init__(self, model: T, repository: TRepo, dialect: Dialect) -> None:
21
+ super().__init__(model, repository, dialect=dialect)
18
22
 
19
23
  @override
20
24
  @property
@@ -25,7 +29,7 @@ class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase]):
25
29
  def execute(self) -> None:
26
30
  if not self._query:
27
31
  raise ValueError
28
- return self._repository.executemany_with_values(self.query, self._values)
32
+ return self._repository.executemany_with_values(self.query(self._dialect), self._values)
29
33
 
30
34
  @override
31
35
  def insert[TProp](self, instances: T | list[T]) -> None:
@@ -39,7 +43,7 @@ class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase]):
39
43
  col_values: list[list[str]] = []
40
44
  for i, cols in enumerate(valid_cols):
41
45
  col_values.append([])
42
- CASTER = Caster(self._repository)
46
+ CASTER = self._dialect.caster()
43
47
  for col in cols:
44
48
  clean_data = CASTER.for_column(col, instances[i]) # .resolve(instances[i][col])
45
49
  if i == 0:
@@ -95,3 +99,6 @@ class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase]):
95
99
  else:
96
100
  raise Exception(f"Tipo de dato'{type(values)}' no esperado")
97
101
  return None
102
+
103
+
104
+ __all__ = ["Insert"]
@@ -0,0 +1,5 @@
1
+ from .IDelete import IDelete # noqa: F401
2
+ from .IInsert import IInsert # noqa: F401
3
+ from .ISelect import ISelect # noqa: F401
4
+ from .IUpdate import IUpdate # noqa: F401
5
+ from .IUpsert import IUpsert # noqa: F401
@@ -11,24 +11,32 @@ if TYPE_CHECKING:
11
11
  from ormlambda import Table
12
12
  from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
13
13
  from ormlambda.common.enums.join_type import JoinType
14
+ from ormlambda.dialects import Dialect
14
15
 
15
16
 
16
- type TupleJoinType[LTable: Table, LProp, RTable: Table, RProp] = tuple[Comparer[LTable, LProp, RTable, RProp], JoinType]
17
+ type TupleJoinType[LTable: Table, LProp, RTable: Table, RProp] = tuple[Comparer]
17
18
 
18
19
 
19
20
  class JoinContext[TParent: Table, TRepo]:
20
- def __init__(self, statements: IStatements_two_generic[TParent, TRepo], joins: tuple, context: ClauseContextType) -> None:
21
+ def __init__(
22
+ self,
23
+ statements: IStatements_two_generic[TParent, TRepo],
24
+ joins: tuple,
25
+ context: ClauseContextType,
26
+ dialect: Dialect,
27
+ ) -> None:
21
28
  self._statements = statements
22
29
  self._parent: TParent = statements.model
23
30
  self._joins: Iterable[tuple[Comparer, JoinType]] = joins
24
31
  self._context: ClauseContextType = context
32
+ self._dialect: Dialect = dialect
25
33
 
26
34
  def __enter__(self) -> IStatements_two_generic[TParent, TRepo]:
27
35
  for comparer, by in self._joins:
28
36
  fk_clause, alias = self.get_fk_clause(comparer)
29
37
 
30
- foreign_key: ForeignKey = ForeignKey(comparer=comparer, clause_name=alias, keep_alive=True)
31
- fk_clause.alias_table = foreign_key.alias
38
+ foreign_key: ForeignKey = ForeignKey(comparer=comparer, clause_name=alias, keep_alive=True, dialect=self._dialect)
39
+ fk_clause.alias_table = foreign_key.get_alias(self._dialect)
32
40
  self._context.add_clause_to_context(fk_clause)
33
41
  setattr(self._parent, alias, foreign_key)
34
42
 
@@ -64,10 +72,10 @@ class JoinContext[TParent: Table, TRepo]:
64
72
  >>> (A.fk_b == B.pk_b) & (B.fk_c == C.pk_c) # Incorrect
65
73
  """
66
74
  clause_dicc: dict[Table, ClauseInfo] = {
67
- comparer.left_condition.table: comparer.left_condition,
68
- comparer.right_condition.table: comparer.right_condition,
75
+ comparer.left_condition(self._dialect).table: comparer.left_condition(self._dialect),
76
+ comparer.right_condition(self._dialect).table: comparer.right_condition(self._dialect),
69
77
  }
70
- conditions = set([comparer.left_condition.table, comparer.right_condition.table])
78
+ conditions = set([comparer.left_condition(self._dialect).table, comparer.right_condition(self._dialect).table])
71
79
  model = set([self._statements.model])
72
80
 
73
81
  parent_table = conditions.difference(model).pop()