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,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
@@ -0,0 +1 @@
1
+ from .join_context import JoinContext, TupleJoinType # 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()
@@ -3,20 +3,24 @@ from collections import defaultdict
3
3
  from typing import override, Optional, TYPE_CHECKING, Type
4
4
 
5
5
 
6
- from ormlambda.utils.module_tree.dfs_traversal import DFSTraversal
6
+ from ormlambda.util.module_tree.dfs_traversal import DFSTraversal
7
7
  from ormlambda.common.interfaces.IJoinSelector import IJoinSelector
8
8
  from ormlambda.common.interfaces.IQueryCommand import IQuery
9
9
  from ormlambda import JoinType
10
10
  from ormlambda.sql.clause_info import ClauseInfo
11
11
  from ormlambda.sql.comparer import Comparer
12
12
  from ormlambda.sql.clause_info.clause_info_context import ClauseInfoContext, ClauseContextType
13
+ from ormlambda.sql.elements import ClauseElement
14
+
13
15
 
14
16
  # TODOL [x]: Try to import Table module without circular import Error
15
17
  if TYPE_CHECKING:
16
18
  from ormlambda import Table
19
+ from ormlambda.dialects import Dialect
17
20
 
18
21
 
19
- class JoinSelector[TLeft: Table, TRight: Table](IJoinSelector[TLeft, TRight]):
22
+ class JoinSelector[TLeft: Table, TRight: Table](IJoinSelector[TLeft, TRight], ClauseElement):
23
+ __visit_name__ = "join"
20
24
  __slots__: tuple = (
21
25
  "_comparer",
22
26
  "_orig_table",
@@ -37,26 +41,31 @@ class JoinSelector[TLeft: Table, TRight: Table](IJoinSelector[TLeft, TRight]):
37
41
 
38
42
  def __init__[LProp, RProp](
39
43
  self,
40
- where: Comparer[TLeft, LProp, TRight, RProp],
44
+ where: Comparer,
41
45
  by: JoinType,
42
46
  alias: Optional[str] = "{table}",
43
47
  context: ClauseContextType = None,
48
+ *,
49
+ dialect: Dialect,
50
+ **kw,
44
51
  ) -> None:
45
- self._comparer: Comparer[TLeft, LProp, TRight, RProp] = where
46
- self._orig_table: TLeft = where.left_condition.table
47
- self._right_table: TRight = where.right_condition.table
52
+ lcon = where.left_condition(dialect)
53
+ rcon = where.right_condition(dialect)
54
+ self._comparer: Comparer = where
55
+ self._orig_table: TLeft = lcon.table
56
+ self._right_table: TRight = rcon.table
48
57
  self._by: JoinType = by
49
- self._left_col: str = where.left_condition._column.column_name
50
- self._right_col: str = where.right_condition._column.column_name
58
+ self._left_col: str = lcon._column.column_name
59
+ self._right_col: str = rcon._column.column_name
51
60
  self._compareop = where._compare
52
61
  self._context: ClauseContextType = context if context else ClauseInfoContext()
53
62
 
54
63
  # COMMENT: When multiple columns reference the same table, we need to create an alias to maintain clear references.
55
64
  self._alias: Optional[str] = alias
56
65
 
57
- self._from_clause = ClauseInfo(self.right_table, alias_table=alias, context=self._context)
58
- self._left_table_clause = ClauseInfo(self.left_table, column=self.left_col, alias_clause=None, context=self._create_partial_context())
59
- self._right_table_clause = ClauseInfo(self.right_table, column=self.right_col, alias_clause=None, context=self._create_partial_context())
66
+ self._from_clause = ClauseInfo(self.right_table, alias_table=alias, context=self._context, dialect=dialect, **kw)
67
+ self._left_table_clause = ClauseInfo(self.left_table, column=self.left_col, alias_clause=None, context=self._create_partial_context(), dialect=dialect, **kw)
68
+ self._right_table_clause = ClauseInfo(self.right_table, column=self.right_col, alias_clause=None, context=self._create_partial_context(), dialect=dialect, **kw)
60
69
 
61
70
  def __eq__(self, __value: JoinSelector) -> bool:
62
71
  return isinstance(__value, JoinSelector) and self.__hash__() == __value.__hash__()
@@ -82,20 +91,18 @@ class JoinSelector[TLeft: Table, TRight: Table](IJoinSelector[TLeft, TRight]):
82
91
  return ClauseInfoContext(clause_context=None, table_context=self._context._table_context)
83
92
 
84
93
  @classmethod
85
- def join_selectors(cls, *args: JoinSelector) -> str:
86
- return "\n".join([x.query for x in args])
94
+ def join_selectors(cls, dialect: Dialect, *args: JoinSelector) -> str:
95
+ return "\n".join([x.query(dialect) for x in args])
87
96
 
88
- @property
89
- @override
90
- def query(self) -> str:
97
+ def query(self, dialect: Dialect, **kwargs) -> str:
91
98
  self._context = ClauseInfoContext(clause_context=None, table_context=self._context._table_context)
92
99
  list_ = [
93
100
  self._by.value, # inner join
94
- self._from_clause.query,
101
+ self._from_clause.query(dialect, **kwargs),
95
102
  "ON",
96
- self._left_table_clause.query,
103
+ self._left_table_clause.query(dialect, **kwargs),
97
104
  self._compareop, # =
98
- self._right_table_clause.query,
105
+ self._right_table_clause.query(dialect, **kwargs),
99
106
  ]
100
107
  return " ".join([x for x in list_ if x is not None])
101
108
 
@@ -147,3 +154,6 @@ class JoinSelector[TLeft: Table, TRight: Table](IJoinSelector[TLeft, TRight]):
147
154
  continue
148
155
  res.extend(tables)
149
156
  return res
157
+
158
+
159
+ __all__ = ["JoinSelector"]
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+ from ormlambda.sql.elements import ClauseElement
3
+
4
+
5
+ class Limit(ClauseElement):
6
+ __visit_name__ = "limit"
7
+ LIMIT = "LIMIT"
8
+
9
+ def __init__(self, number: int, **kwargs) -> None:
10
+ if not isinstance(number, int):
11
+ raise ValueError
12
+ self._number: int = number
13
+
14
+
15
+ __all__ = ["Limit"]
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+ from ormlambda.sql.elements import ClauseElement
3
+
4
+
5
+ class Offset(ClauseElement):
6
+ __visit_name__ = "offset"
7
+ OFFSET = "OFFSET"
8
+
9
+ def __init__(self, number: int, **kwargs) -> None:
10
+ if not isinstance(number, int):
11
+ raise ValueError
12
+ self._number: int = number
13
+
14
+
15
+ __all__ = ["Offset"]
@@ -1,14 +1,20 @@
1
1
  from __future__ import annotations
2
2
  import typing as tp
3
3
 
4
- from ormlambda.sql.clause_info.clause_info_context import ClauseInfoContext, ClauseContextType
4
+ from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
5
5
  from ormlambda.sql.types import ColumnType
6
6
  from ormlambda.sql.clause_info import AggregateFunctionBase
7
7
 
8
8
  from ormlambda.statements import OrderType
9
+ from ormlambda.sql.elements import ClauseElement
9
10
 
11
+ if tp.TYPE_CHECKING:
12
+ from ormlambda.dialects import Dialect
13
+
14
+
15
+ class Order(AggregateFunctionBase, ClauseElement):
16
+ __visit_name__ = "order"
10
17
 
11
- class Order(AggregateFunctionBase):
12
18
  @staticmethod
13
19
  def FUNCTION_NAME() -> str:
14
20
  return "ORDER BY"
@@ -18,11 +24,16 @@ class Order(AggregateFunctionBase):
18
24
  column: tuple[ColumnType[TProp], ...] | ColumnType[TProp],
19
25
  order_type: tp.Iterable[OrderType],
20
26
  context: ClauseContextType = None,
27
+ *,
28
+ dialect: Dialect,
29
+ **kw,
21
30
  ):
22
31
  super().__init__(
23
32
  table=None,
24
33
  column=column,
25
34
  context=context,
35
+ dialect=dialect,
36
+ **kw,
26
37
  )
27
38
 
28
39
  if isinstance(order_type, str) or not isinstance(order_type, tp.Iterable):
@@ -41,25 +52,4 @@ class Order(AggregateFunctionBase):
41
52
  pass
42
53
  raise Exception(f"order_type param only can be 'ASC' or 'DESC' string or '{OrderType.__name__}' enum")
43
54
 
44
- @tp.override
45
- @property
46
- def query(self) -> str:
47
- string_columns: list[str] = []
48
- columns = self.unresolved_column
49
-
50
- # if this attr is not iterable means that we only pass one column without wrapped in a list or tuple
51
- if isinstance(columns, str):
52
- string_columns = f"{columns} {str(self._order_type[0])}"
53
- return f"{self.FUNCTION_NAME()} {string_columns}"
54
-
55
- if not isinstance(columns, tp.Iterable):
56
- columns = (columns,)
57
-
58
- assert len(columns) == len(self._order_type)
59
-
60
- context = ClauseInfoContext(table_context=self._context._table_context, clause_context=None) if self._context else None
61
- for index, clause in enumerate(self._convert_into_clauseInfo(columns, context)):
62
- clause.alias_clause = None
63
- string_columns.append(f"{clause.query} {str(self._order_type[index])}")
64
-
65
- return f"{self.FUNCTION_NAME()} {', '.join(string_columns)}"
55
+ __all__ = ["Order"]
@@ -1,17 +1,20 @@
1
1
  from __future__ import annotations
2
- from typing import Optional, override, Type, Callable, TYPE_CHECKING
2
+ from ormlambda.sql.elements import ClauseElement
3
+ from typing import Optional, Type, Callable, TYPE_CHECKING
3
4
 
4
5
  from ormlambda.sql.clause_info import ClauseInfo
5
6
  from ormlambda.sql.clause_info.clause_info_context import ClauseInfoContext
6
7
  from ormlambda.sql.types import AliasType
7
8
  from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase
8
- from ormlambda.components import ISelect
9
9
 
10
10
  if TYPE_CHECKING:
11
11
  from ormlambda import Table
12
+ from ormlambda.dialects import Dialect
12
13
 
13
14
 
14
- class Select[T: Type[Table], *Ts](DecompositionQueryBase[T, *Ts], ISelect):
15
+ class Select[T: Type[Table], *Ts](DecompositionQueryBase[T, *Ts], ClauseElement):
16
+ __visit_name__ = "select"
17
+
15
18
  CLAUSE: str = "SELECT"
16
19
 
17
20
  def __init__(
@@ -21,11 +24,15 @@ class Select[T: Type[Table], *Ts](DecompositionQueryBase[T, *Ts], ISelect):
21
24
  *,
22
25
  alias_table: AliasType[ClauseInfo] = "{table}",
23
26
  context: Optional[ClauseInfoContext] = None,
27
+ dialect: Dialect,
28
+ **kwargs,
24
29
  ) -> None:
25
30
  super().__init__(
26
31
  tables,
27
32
  columns,
28
33
  context=context,
34
+ dialect=dialect,
35
+ **kwargs,
29
36
  )
30
37
  self._alias_table = alias_table
31
38
  # We always need to add the self alias of the Select
@@ -33,18 +40,12 @@ class Select[T: Type[Table], *Ts](DecompositionQueryBase[T, *Ts], ISelect):
33
40
 
34
41
  @property
35
42
  def FROM(self) -> ClauseInfo[T]:
36
- return ClauseInfo(self.table, None, alias_table=self._alias_table, context=self._context)
43
+ return ClauseInfo(self.table, None, alias_table=self._alias_table, context=self._context, dialect=self._dialect, **self.kwargs)
37
44
 
38
45
  @property
39
46
  def COLUMNS(self) -> str:
40
- return ClauseInfo.join_clauses(self._all_clauses, ",", self.context)
47
+ dialect = self.kwargs.pop("dialect", self._dialect)
48
+ return ClauseInfo.join_clauses(self._all_clauses, ",", self.context, dialect=dialect)
41
49
 
42
- # TODOL: see who to deal when we will have to add more mysql methods
43
- @override
44
- @property
45
- def query(self) -> str:
46
- # COMMENT: (select.query, query)We must first create an alias for 'FROM' and then define all the remaining clauses.
47
- # This order is mandatory because it adds the clause name to the context when accessing the .query property of 'FROM'
48
- FROM = self.FROM
49
50
 
50
- return f"{self.CLAUSE} {self.COLUMNS} FROM {FROM.query}"
51
+ __all__ = ["Select"]
@@ -1,11 +1,18 @@
1
- from typing import Type, override, Any
1
+ from __future__ import annotations
2
+ from typing import Type, override, Any, TYPE_CHECKING, Optional
2
3
 
3
- from ormlambda.components.update import UpdateQueryBase
4
4
  from ormlambda import Table, Column
5
- from ormlambda.repository import IRepositoryBase
6
5
  from ormlambda.caster.caster import Caster
7
6
  from .where import Where
8
- from ormlambda.sql.types import ColumnType
7
+ from ormlambda.common.abstract_classes import NonQueryBase
8
+ from .interfaces import IUpdate
9
+
10
+ if TYPE_CHECKING:
11
+ from ormlambda.sql.types import ColumnType
12
+ from .where import Where
13
+ from ormlambda.engine import Engine
14
+
15
+ from ormlambda.sql.elements import ClauseElement
9
16
 
10
17
 
11
18
  class UpdateKeyError(KeyError):
@@ -20,9 +27,12 @@ class UpdateKeyError(KeyError):
20
27
  return f"The column '{self._key}' does not belong to the table '{self._table.__table_name__}'. Please check the columns in the query."
21
28
 
22
29
 
23
- class UpdateQuery[T: Type[Table]](UpdateQueryBase[T, IRepositoryBase]):
24
- def __init__(self, model: T, repository: Any, where: list[Where]) -> None:
25
- super().__init__(model, repository, where)
30
+ class Update[T: Type[Table], TRepo](NonQueryBase[T, TRepo], IUpdate, ClauseElement):
31
+ __visit_name__ = "update"
32
+
33
+ def __init__(self, model: T, repository: Any, where: list[Where], engine: Engine) -> None:
34
+ super().__init__(model, repository, engine=engine)
35
+ self._where: Optional[list[Where]] = where
26
36
 
27
37
  @override
28
38
  @property
@@ -33,11 +43,11 @@ class UpdateQuery[T: Type[Table]](UpdateQueryBase[T, IRepositoryBase]):
33
43
  def execute(self) -> None:
34
44
  if self._where:
35
45
  for where in self._where:
36
- query_with_table = where.query
46
+ query_with_table = where.query(self._engine.dialect)
37
47
  for x in where._comparer:
38
48
  # TODOH []: Refactor this part. We need to get only the columns withouth __table_name__ preffix
39
- self._query += " " + query_with_table.replace(x.left_condition.table.__table_name__ + ".", "")
40
- return self._repository.execute_with_values(self._query, self._values)
49
+ self._query += " " + query_with_table.replace(x.left_condition(self._dialect).table.__table_name__ + ".", "")
50
+ return self._engine.repository.execute_with_values(self._query, self._values)
41
51
 
42
52
  @override
43
53
  def update[TProp](self, dicc: dict[str | ColumnType[TProp], Any]) -> None:
@@ -45,7 +55,7 @@ class UpdateQuery[T: Type[Table]](UpdateQueryBase[T, IRepositoryBase]):
45
55
  raise TypeError
46
56
 
47
57
  col_names: list[Column] = []
48
- CASTER = Caster(self._repository)
58
+ CASTER = self._engine.dialect.caster()
49
59
  for col, value in dicc.items():
50
60
  if isinstance(col, str):
51
61
  if not hasattr(self._model, col):
@@ -69,3 +79,6 @@ class UpdateQuery[T: Type[Table]](UpdateQueryBase[T, IRepositoryBase]):
69
79
  if self._model is not col.table:
70
80
  raise UpdateKeyError(self._model, col)
71
81
  return not col.is_auto_generated
82
+
83
+
84
+ __all__ = ["Update"]
@@ -1,16 +1,22 @@
1
- from typing import override, Any
1
+ from __future__ import annotations
2
+ from typing import override, TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from ormlambda.engine import Engine
2
6
 
3
7
  from ormlambda import Table
4
- from ormlambda.components.upsert import UpsertQueryBase
5
- from ormlambda.repository import IRepositoryBase
6
- from mysql.connector import MySQLConnection
8
+ from ormlambda.repository import BaseRepository
9
+ from ormlambda.sql.clauses.interfaces import IUpsert
10
+ from ormlambda.common.abstract_classes import NonQueryBase
11
+ from .insert import Insert
12
+ from ormlambda.sql.elements import ClauseElement
7
13
 
8
- from .insert import InsertQuery
9
14
 
15
+ class Upsert[T: Table, TRepo](NonQueryBase[T, TRepo], IUpsert[T], ClauseElement):
16
+ __visit_name__ = "upsert"
10
17
 
11
- class UpsertQuery[T: Table](UpsertQueryBase[T, IRepositoryBase]):
12
- def __init__(self, model: T, repository: Any) -> None:
13
- super().__init__(model, repository)
18
+ def __init__(self, model: T, repository: BaseRepository[TRepo], engine: Engine) -> None:
19
+ super().__init__(model, repository, engine=engine)
14
20
 
15
21
  @override
16
22
  @property
@@ -19,7 +25,7 @@ class UpsertQuery[T: Table](UpsertQueryBase[T, IRepositoryBase]):
19
25
 
20
26
  @override
21
27
  def execute(self) -> None:
22
- return self._repository.executemany_with_values(self._query, self._values)
28
+ return self._engine.repository.executemany_with_values(self._query, self._values)
23
29
 
24
30
  @override
25
31
  def upsert(self, instances: T | list[T]) -> None:
@@ -50,7 +56,7 @@ class UpsertQuery[T: Table](UpsertQueryBase[T, IRepositoryBase]):
50
56
  COL2 = _val.COL2;
51
57
 
52
58
  """
53
- insert = InsertQuery[T](self._model, self._repository)
59
+ insert = Insert(self._model, self._engine.repository, self._engine.dialect)
54
60
  insert.insert(instances)
55
61
 
56
62
  if isinstance(instances, Table):
@@ -66,3 +72,6 @@ class UpsertQuery[T: Table](UpsertQueryBase[T, IRepositoryBase]):
66
72
  self._query = query
67
73
  self._values = insert.values
68
74
  return None
75
+
76
+
77
+ __all__ = ["Upsert"]