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
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
  from typing import Any, Callable, Optional, Type, overload, TYPE_CHECKING
3
3
  from enum import Enum
4
- from abc import abstractmethod, ABC
4
+ from abc import abstractmethod
5
5
 
6
6
 
7
7
  if TYPE_CHECKING:
@@ -9,12 +9,11 @@ if TYPE_CHECKING:
9
9
  from ormlambda import Table
10
10
  from ormlambda.sql.clause_info import IAggregate
11
11
  from ormlambda.sql.types import TupleJoinType, ColumnType
12
- from ormlambda.components.join import JoinContext
12
+ from ormlambda.sql.clauses.join import JoinContext
13
13
  from ormlambda.common.enums import JoinType
14
14
  from ormlambda.sql.clause_info import ClauseInfo
15
15
  from ormlambda.sql.types import AliasType
16
16
 
17
-
18
17
  from ..types import (
19
18
  OrderTypes,
20
19
  Tuple,
@@ -31,12 +30,16 @@ from ..types import (
31
30
  WhereTypes,
32
31
  SelectCols,
33
32
  )
33
+ from ormlambda.sql.elements import Element
34
34
 
35
35
 
36
- class IStatements[T: Table](ABC):
36
+ class IStatements[T: Table](Element):
37
37
  @abstractmethod
38
38
  def create_table(self, if_exists: TypeExists = "fail") -> None: ...
39
39
 
40
+ @abstractmethod
41
+ def drop_table(self) -> None: ...
42
+
40
43
  # #TODOL [ ]: We must to implement this mehtod
41
44
  # @abstractmethod
42
45
  # def drop_table(self)->None: ...
@@ -334,6 +337,7 @@ class IStatements_two_generic[T, TPool](IStatements[T]):
334
337
  def repository(self) -> BaseRepository[TPool]: ...
335
338
 
336
339
  @property
340
+ @abstractmethod
337
341
  def query(self) -> str: ...
338
342
 
339
343
  @property
@@ -1,25 +1,29 @@
1
1
  from __future__ import annotations
2
- from typing import Iterable, TypedDict, Optional
2
+ from typing import Iterable, TypedDict, Optional, TYPE_CHECKING
3
3
 
4
4
  from ormlambda.sql.clause_info.clause_info_context import ClauseInfoContext
5
- from ormlambda.databases.my_sql.clauses.joins import JoinSelector
5
+ from ormlambda.sql.clauses import JoinSelector
6
6
  from ormlambda import ForeignKey
7
7
 
8
8
  from ormlambda.common.interfaces import IQuery
9
9
 
10
10
 
11
11
  from ormlambda.sql.clause_info import ClauseInfo
12
- from .clauses import Limit
13
- from .clauses import Offset
14
- from .clauses import Order
15
- from .clauses import Select
16
12
 
17
- from .clauses import Where
18
- from .clauses import Having
19
- from .clauses import GroupBy
13
+ if TYPE_CHECKING:
14
+ from ..sql.clauses import Limit as Limit
15
+ from ..sql.clauses import Offset as Offset
16
+ from ..sql.clauses import Order as Order
17
+ from ..sql.clauses import Select as Select
20
18
 
19
+ from ..sql.clauses import GroupBy as GroupBy
21
20
 
21
+ from ormlambda.dialects import Dialect
22
+
23
+ from ..sql.clauses import Where as Where
24
+ from ..sql.clauses import Having as Having
22
25
  from ormlambda.common.enums import JoinType
26
+ from ormlambda.sql.elements import ClauseElement
23
27
 
24
28
 
25
29
  class OrderType(TypedDict):
@@ -36,7 +40,8 @@ class OrderType(TypedDict):
36
40
  class QueryBuilder(IQuery):
37
41
  __order__: tuple[str, ...] = ("Select", "JoinSelector", "Where", "GroupBy", "Having", "Order", "Limit", "Offset")
38
42
 
39
- def __init__(self, by: JoinType = JoinType.INNER_JOIN):
43
+ def __init__(self, dialect: Dialect, by: JoinType = JoinType.INNER_JOIN):
44
+ self.dialect = dialect
40
45
  self._context = ClauseInfoContext()
41
46
  self._query_list: OrderType = {}
42
47
  self._by = by
@@ -66,11 +71,11 @@ class QueryBuilder(IQuery):
66
71
  return self._joins
67
72
 
68
73
  @property
69
- def SELECT(self) -> IQuery:
74
+ def SELECT(self) -> ClauseElement:
70
75
  return self._query_list.get("Select", None)
71
76
 
72
77
  @property
73
- def WHERE(self) -> IQuery:
78
+ def WHERE(self) -> ClauseElement:
74
79
  where = self._query_list.get("Where", None)
75
80
  if not isinstance(where, Iterable):
76
81
  if not where:
@@ -79,15 +84,15 @@ class QueryBuilder(IQuery):
79
84
  return where
80
85
 
81
86
  @property
82
- def ORDER(self) -> IQuery:
87
+ def ORDER(self) -> ClauseElement:
83
88
  return self._query_list.get("Order", None)
84
89
 
85
90
  @property
86
- def GROUP_BY(self) -> IQuery:
91
+ def GROUP_BY(self) -> ClauseElement:
87
92
  return self._query_list.get("GroupBy", None)
88
93
 
89
94
  @property
90
- def HAVING(self) -> IQuery:
95
+ def HAVING(self) -> ClauseElement:
91
96
  where = self._query_list.get("Having", None)
92
97
  if not isinstance(where, Iterable):
93
98
  if not where:
@@ -96,15 +101,14 @@ class QueryBuilder(IQuery):
96
101
  return where
97
102
 
98
103
  @property
99
- def LIMIT(self) -> IQuery:
104
+ def LIMIT(self) -> ClauseElement:
100
105
  return self._query_list.get("Limit", None)
101
106
 
102
107
  @property
103
- def OFFSET(self) -> IQuery:
108
+ def OFFSET(self) -> ClauseElement:
104
109
  return self._query_list.get("Offset", None)
105
110
 
106
- @property
107
- def query(self) -> str:
111
+ def query(self, dialect: Dialect, **kwargs) -> str:
108
112
  # COMMENT: (select.query, query)We must first create an alias for 'FROM' and then define all the remaining clauses.
109
113
  # This order is mandatory because it adds the clause name to the context when accessing the .query property of 'FROM'
110
114
 
@@ -112,14 +116,14 @@ class QueryBuilder(IQuery):
112
116
 
113
117
  JOINS = self.stringify_foreign_key(extract_joins, " ")
114
118
  query_list: tuple[str, ...] = (
115
- self.SELECT.query,
119
+ self.SELECT.compile(dialect).string,
116
120
  JOINS,
117
- Where.join_condition(self.WHERE, True, self._context) if self.WHERE else None,
118
- self.GROUP_BY.query if self.GROUP_BY else None,
119
- Having.join_condition(self.HAVING, True, self._context) if self.HAVING else None,
120
- self.ORDER.query if self.ORDER else None,
121
- self.LIMIT.query if self.LIMIT else None,
122
- self.OFFSET.query if self.OFFSET else None,
121
+ Where.join_condition(self.WHERE, True, self._context, dialect=dialect) if self.WHERE else None,
122
+ self.GROUP_BY.compile(dialect).string if self.GROUP_BY else None,
123
+ Having.join_condition(self.HAVING, True, self._context, dialect=dialect) if self.HAVING else None,
124
+ self.ORDER.compile(dialect).string if self.ORDER else None,
125
+ self.LIMIT.compile(dialect).string if self.LIMIT else None,
126
+ self.OFFSET.compile(dialect).string if self.OFFSET else None,
123
127
  )
124
128
  return " ".join([x for x in query_list if x])
125
129
 
@@ -127,7 +131,7 @@ class QueryBuilder(IQuery):
127
131
  if not joins:
128
132
  return None
129
133
  sorted_joins = JoinSelector.sort_join_selectors(joins)
130
- return f"{sep}".join([join.query for join in sorted_joins])
134
+ return f"{sep}".join([join.query(self.dialect) for join in sorted_joins])
131
135
 
132
136
  def pop_tables_and_create_joins_from_ForeignKey(self, by: JoinType = JoinType.INNER_JOIN) -> set[JoinSelector]:
133
137
  # When we applied filters in any table that we wont select any column, we need to add manually all neccessary joins to achieve positive result.
@@ -139,14 +143,15 @@ class QueryBuilder(IQuery):
139
143
  # FIXME [x]: Resolved when we get Compare object instead ClauseInfo. For instance, when we have multiples condition using '&' or '|'
140
144
  for fk in ForeignKey.stored_calls.copy():
141
145
  fk = ForeignKey.stored_calls.pop(fk)
142
- self._context._add_table_alias(fk.tright, fk.alias)
143
- join = JoinSelector(fk.resolved_function(self._context), by, context=self._context, alias=fk.alias)
146
+ fk_alias = fk.get_alias(self.dialect)
147
+ self._context._add_table_alias(fk.tright, fk_alias)
148
+ join = JoinSelector(fk.resolved_function(self._context), by, context=self._context, alias=fk_alias, dialect=self.dialect)
144
149
  joins.add(join)
145
150
 
146
151
  return joins
147
152
 
148
153
  def clear(self) -> None:
149
- self.__init__()
154
+ self.__init__(self.dialect, self.by)
150
155
  return None
151
156
 
152
157
  def update_context(self, clause: ClauseInfo) -> None:
@@ -1,19 +1,16 @@
1
1
  from __future__ import annotations
2
2
  from typing import Concatenate, Iterable, override, Type, TYPE_CHECKING, Any, Callable, Optional
3
- from mysql.connector import errors, errorcode
4
3
 
5
4
  from ormlambda import ForeignKey
6
5
 
7
- from mysql.connector import MySQLConnection
8
-
9
6
 
10
7
  if TYPE_CHECKING:
8
+ from ormlambda.engine.base import Engine
11
9
  from ormlambda.sql.types import AliasType
12
10
  from ormlambda import Table
13
11
  from ormlambda.statements.types import OrderTypes
14
12
  from ormlambda.sql.types import ColumnType
15
13
  from ormlambda.statements.types import SelectCols
16
- from ormlambda.repository import BaseRepository
17
14
  from ormlambda.statements.interfaces import IStatements_two_generic
18
15
  from ormlambda.statements.types import TypeExists
19
16
  from ormlambda.sql.clause_info import IAggregate
@@ -22,35 +19,22 @@ if TYPE_CHECKING:
22
19
 
23
20
  from ormlambda.sql.clause_info import ClauseInfo
24
21
  from ormlambda.statements import BaseStatement
25
- from .clauses import DeleteQuery
26
- from .clauses import InsertQuery
27
- from .clauses import Limit
28
- from .clauses import Offset
29
- from .clauses import Order
30
- from .clauses import Select
31
-
32
- from .clauses import UpsertQuery
33
- from .clauses import UpdateQuery
34
- from .clauses import Where
35
- from .clauses import Having
36
- from .clauses import Count
37
- from .clauses import GroupBy
38
- from .clauses import Alias
39
-
40
22
 
41
23
  from ormlambda import Table, Column
42
24
  from ormlambda.common.enums import JoinType
43
- from . import functions as func
44
- from ormlambda.components.join import JoinContext, TupleJoinType
25
+ from ormlambda.sql.clauses.join import JoinContext, TupleJoinType
45
26
 
46
27
  from ormlambda.common.global_checker import GlobalChecker
47
28
  from .query_builder import QueryBuilder
48
29
 
30
+ from ormlambda.sql import clauses
31
+ from ormlambda.sql import functions as func
32
+
49
33
 
50
34
  # COMMENT: It's so important to prevent information generated by other tests from being retained in the class.
51
35
  @staticmethod
52
- def clear_list[T, **P](f: Callable[Concatenate[MySQLStatements, P], T]) -> Callable[P, T]:
53
- def wrapper(self: MySQLStatements, *args: P.args, **kwargs: P.kwargs) -> T:
36
+ def clear_list[T, **P](f: Callable[Concatenate[Statements, P], T]) -> Callable[P, T]:
37
+ def wrapper(self: Statements, *args: P.args, **kwargs: P.kwargs) -> T:
54
38
  try:
55
39
  return f(self, *args, **kwargs)
56
40
  except Exception as err:
@@ -62,20 +46,20 @@ def clear_list[T, **P](f: Callable[Concatenate[MySQLStatements, P], T]) -> Calla
62
46
  return wrapper
63
47
 
64
48
 
65
- class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
66
- def __init__(self, model: tuple[T, *Ts], repository: BaseRepository) -> None:
67
- super().__init__(model, repository=repository)
68
- self._query_builder = QueryBuilder()
49
+ class Statements[T: Table, TRepo](BaseStatement[T, None]):
50
+ def __init__(self, model: T, engine: Engine) -> None:
51
+ super().__init__(model, engine)
52
+ self._query_builder = QueryBuilder(self.dialect)
69
53
 
70
54
  @override
71
55
  def create_table(self, if_exists: TypeExists = "fail") -> None:
72
56
  name: str = self._model.__table_name__
73
57
  if self._repository.table_exists(name):
74
58
  if if_exists == "replace":
75
- self._repository.drop_table(name)
59
+ self.drop_table()
76
60
 
77
61
  elif if_exists == "fail":
78
- raise errors.ProgrammingError(msg=f"Table '{self._model.__table_name__}' already exists", errno=errorcode.ER_TABLE_EXISTS_ERROR)
62
+ raise ValueError(f"Table '{self._model.__table_name__}' already exists")
79
63
 
80
64
  elif if_exists == "append":
81
65
  counter: int = 0
@@ -84,16 +68,25 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
84
68
  counter += 1
85
69
  char = f"_{counter}"
86
70
  name += char
87
- self._model.__table_name__ = name
88
71
 
89
- query = self._model.create_table_query()
72
+ new_model = self._model
73
+ new_model.__table_name__ = name
74
+ return new_model.create_table(self.dialect)
75
+
76
+ query = self.model.create_table(self.dialect)
90
77
  self._repository.execute(query)
91
78
  return None
92
79
 
80
+ @override
81
+ def drop_table(self)->None:
82
+ q = self.model.drop_table(self.dialect)
83
+ self._repository.execute(q)
84
+ return None
85
+
93
86
  @override
94
87
  @clear_list
95
88
  def insert(self, instances: T | list[T]) -> None:
96
- insert = InsertQuery(self._model, self._repository)
89
+ insert = clauses.Insert(self._model, self.repository, self._dialect)
97
90
  insert.insert(instances)
98
91
  insert.execute()
99
92
  return None
@@ -108,7 +101,7 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
108
101
  # We always going to have a tuple of one element
109
102
  return self.delete(response)
110
103
 
111
- delete = DeleteQuery(self._model, self._repository)
104
+ delete = clauses.Delete(self._model, self._repository, engine=self._engine)
112
105
  delete.delete(instances)
113
106
  delete.execute()
114
107
  # not necessary to call self._query_builder.clear() because select() method already call it
@@ -117,7 +110,7 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
117
110
  @override
118
111
  @clear_list
119
112
  def upsert(self, instances: T | list[T]) -> None:
120
- upsert = UpsertQuery(self._model, self._repository)
113
+ upsert = clauses.Upsert(self._model, self._repository, engine=self._engine)
121
114
  upsert.upsert(instances)
122
115
  upsert.execute()
123
116
  return None
@@ -125,22 +118,22 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
125
118
  @override
126
119
  @clear_list
127
120
  def update(self, dicc: dict[str, Any] | list[dict[str, Any]]) -> None:
128
- update = UpdateQuery(self._model, self._repository, self._query_builder.WHERE)
121
+ update = clauses.Update(self._model, self._repository, self._query_builder.WHERE, engine=self._engine)
129
122
  update.update(dicc)
130
123
  update.execute()
131
124
 
132
125
  return None
133
126
 
134
127
  @override
135
- def limit(self, number: int) -> IStatements_two_generic[T, MySQLConnection]:
136
- limit = Limit(number)
128
+ def limit(self, number: int) -> IStatements_two_generic[T, TRepo]:
129
+ limit = clauses.Limit(number, dialect=self._dialect)
137
130
  # Only can be one LIMIT SQL parameter. We only use the last LimitQuery
138
131
  self._query_builder.add_statement(limit)
139
132
  return self
140
133
 
141
134
  @override
142
- def offset(self, number: int) -> IStatements_two_generic[T, MySQLConnection]:
143
- offset = Offset(number)
135
+ def offset(self, number: int) -> IStatements_two_generic[T, TRepo]:
136
+ offset = clauses.Offset(number, dialect=self._dialect)
144
137
  self._query_builder.add_statement(offset)
145
138
  return self
146
139
 
@@ -155,40 +148,41 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
155
148
  return self.select_one(self.count(selection, alias, False), flavour=dict)[alias]
156
149
 
157
150
  selection = GlobalChecker.resolved_callback_object(selection, self.models)
158
- return Count(element=selection, alias_clause=alias, context=self._query_builder._context)
151
+ return clauses.Count(
152
+ element=selection,
153
+ alias_clause=alias,
154
+ context=self._query_builder._context,
155
+ dialect=self._dialect,
156
+ )
159
157
 
160
158
  @override
161
- def where(self, conditions: WhereTypes) -> IStatements_two_generic[T, MySQLConnection]:
159
+ def where(self, conditions: WhereTypes) -> IStatements_two_generic[T, TRepo]:
162
160
  # FIXME [x]: I've wrapped self._model into tuple to pass it instance attr. Idk if it's correct
163
161
 
164
162
  conditions = GlobalChecker.resolved_callback_object(conditions, self._models)
165
163
  if not isinstance(conditions, Iterable):
166
164
  conditions = (conditions,)
167
- self._query_builder.add_statement(Where(*conditions))
165
+ self._query_builder.add_statement(clauses.Where(*conditions))
168
166
  return self
169
167
 
170
168
  @override
171
- def having(self, conditions: WhereTypes) -> IStatements_two_generic[T, MySQLConnection]:
169
+ def having(self, conditions: WhereTypes) -> IStatements_two_generic[T, TRepo]:
172
170
  conditions = GlobalChecker.resolved_callback_object(conditions, self._models)
173
171
  if not isinstance(conditions, Iterable):
174
172
  conditions = (conditions,)
175
- self._query_builder.add_statement(Having(*conditions))
173
+ self._query_builder.add_statement(clauses.Having(*conditions))
176
174
  return self
177
175
 
178
176
  @override
179
- def order[TValue](self, columns: Callable[[T], TValue], order_type: OrderTypes) -> IStatements_two_generic[T, MySQLConnection]:
177
+ def order[TValue](self, columns: Callable[[T], TValue], order_type: OrderTypes) -> IStatements_two_generic[T, TRepo]:
180
178
  query = GlobalChecker.resolved_callback_object(columns, self._models)
181
- order = Order(query, order_type)
179
+ order = clauses.Order(query, order_type, dialect=self._dialect)
182
180
  self._query_builder.add_statement(order)
183
181
  return self
184
182
 
185
183
  @override
186
184
  def concat(self, selector: SelectCols[T, str], alias: str = "concat") -> IAggregate:
187
- return func.Concat[T](
188
- values=selector,
189
- alias_clause=alias,
190
- context=self._query_builder._context,
191
- )
185
+ return func.Concat(values=selector, alias_clause=alias, context=self._query_builder._context, dialect=self._dialect)
192
186
 
193
187
  @override
194
188
  def max[TProp](
@@ -200,7 +194,7 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
200
194
  column = GlobalChecker.resolved_callback_object(column, self.models)
201
195
  if execute is True:
202
196
  return self.select_one(self.max(column, alias, execute=False), flavour=dict)[alias]
203
- return func.Max(elements=column, alias_clause=alias, context=self._query_builder._context)
197
+ return func.Max(elements=column, alias_clause=alias, context=self._query_builder._context, dialect=self._dialect)
204
198
 
205
199
  @override
206
200
  def min[TProp](
@@ -212,7 +206,7 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
212
206
  column = GlobalChecker.resolved_callback_object(column, self.models)
213
207
  if execute is True:
214
208
  return self.select_one(self.min(column, alias, execute=False), flavour=dict)[alias]
215
- return func.Min(elements=column, alias_clause=alias, context=self._query_builder._context)
209
+ return func.Min(elements=column, alias_clause=alias, context=self._query_builder._context, dialect=self._dialect)
216
210
 
217
211
  @override
218
212
  def sum[TProp](
@@ -224,11 +218,11 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
224
218
  column = GlobalChecker.resolved_callback_object(column, self.models)
225
219
  if execute is True:
226
220
  return self.select_one(self.sum(column, alias, execute=False), flavour=dict)[alias]
227
- return func.Sum(elements=column, alias_clause=alias, context=self._query_builder._context)
221
+ return func.Sum(elements=column, alias_clause=alias, context=self._query_builder._context, dialect=self._dialect)
228
222
 
229
223
  @override
230
224
  def join[LTable: Table, LProp, RTable: Table, RProp](self, joins: tuple[TupleJoinType[LTable, LProp, RTable, RProp]]) -> JoinContext[tuple[*TupleJoinType[LTable, LProp, RTable, RProp]]]:
231
- return JoinContext(self, joins, self._query_builder._context)
225
+ return JoinContext(self, joins, self._query_builder._context, self._dialect)
232
226
 
233
227
  @override
234
228
  @clear_list
@@ -254,15 +248,16 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
254
248
  return result
255
249
  return () if not result else result[0]
256
250
 
257
- select = Select[T, *Ts](
251
+ select = clauses.Select(
258
252
  self._models,
259
253
  columns=select_clause,
254
+ dialect=self.dialect,
260
255
  **kwargs,
261
256
  )
262
257
  self._query_builder.add_statement(select)
263
258
 
264
259
  self._query_builder.by = by
265
- self._query: str = self._query_builder.query
260
+ self._query: str = self._query_builder.query(self._dialect)
266
261
 
267
262
  if flavour:
268
263
  result = self._return_flavour(self.query, flavour, select, **kwargs)
@@ -316,21 +311,22 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
316
311
  )
317
312
 
318
313
  @override
319
- def groupby[TProp](self, column: ColumnType[TProp] | Callable[[T, *Ts], Any]) -> IStatements_two_generic[T]:
314
+ def groupby[TProp](self, column: ColumnType[TProp] | Callable[[T], Any]) -> IStatements_two_generic[T]:
320
315
  column = GlobalChecker.resolved_callback_object(column, self.models)
321
316
 
322
- groupby = GroupBy(column=column, context=self._query_builder._context)
317
+ groupby = clauses.GroupBy(column=column, context=self._query_builder._context, dialect=self.dialect)
323
318
  # Only can be one LIMIT SQL parameter. We only use the last LimitQuery
324
319
  self._query_builder.add_statement(groupby)
325
320
  return self
326
321
 
327
322
  @override
328
- def alias[TProp](self, column: SelectCols[T, TProp], alias: AliasType[ClauseInfo[T]]) -> ClauseInfo[T]:
323
+ def alias[TProp](self, column: SelectCols[T, TProp], alias: AliasType[ClauseInfo[T]]) -> clauses.Alias[T]:
329
324
  column = GlobalChecker.resolved_callback_object(column, self.models)
330
325
 
331
- return Alias(
326
+ return clauses.Alias(
332
327
  table=column.table,
333
328
  column=column,
334
329
  alias_clause=alias,
335
330
  context=self._query_builder._context,
331
+ dialect=self.dialect,
336
332
  )
@@ -48,8 +48,8 @@ type TypeExists = Literal["fail", "replace", "append"]
48
48
 
49
49
  type WhereTypes[LTable, LProp, RTable, RProp] = Union[
50
50
  bool,
51
- Comparer[LTable, LProp, RTable, RProp],
52
- tuple[Comparer[LTable, LProp, RTable, RProp], ...],
51
+ Comparer,
52
+ tuple[Comparer],
53
53
  Callable[[LTable], WhereTypes[LTable, LProp, RTable, RProp]],
54
54
  ]
55
55
 
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ from .metadata import (
5
+ PrimaryKey,
6
+ AutoGenerated,
7
+ AutoIncrement,
8
+ Unique,
9
+ CheckTypes,
10
+ Default,
11
+ NotNull,
12
+ )
13
+
14
+
15
+ __all__ = [
16
+ "PrimaryKey",
17
+ "AutoGenerated",
18
+ "AutoIncrement",
19
+ "Unique",
20
+ "CheckTypes",
21
+ "Default",
22
+ "NotNull",
23
+ "Binary",
24
+ ]
@@ -0,0 +1,42 @@
1
+ class PrimaryKey:
2
+ """Marks a column as a primary key"""
3
+
4
+ ...
5
+
6
+
7
+ class AutoGenerated:
8
+ """Marks a column as auto-generated"""
9
+
10
+ ...
11
+
12
+
13
+ class AutoIncrement:
14
+ """Marks a column as auto-increment"""
15
+
16
+ ...
17
+
18
+
19
+ class Unique:
20
+ """Marks a column as unique"""
21
+
22
+ ...
23
+
24
+
25
+ class CheckTypes:
26
+ """Controls type checking for this column"""
27
+
28
+ def __init__(self, enabled: bool = True):
29
+ self.enabled: bool = enabled
30
+
31
+
32
+ class Default[T]:
33
+ """Sets a default value for a column"""
34
+
35
+ def __init__(self, value: T):
36
+ self.value: T = value
37
+
38
+
39
+ class NotNull:
40
+ """Marks a column as not-null"""
41
+
42
+ ...
@@ -0,0 +1,87 @@
1
+ from .module_tree import ModuleTree # noqa: F401
2
+ import types
3
+ import inspect
4
+ from typing import Any, Literal, Optional, overload, get_origin, TypeGuard, TypeAliasType
5
+ from ormlambda.util.typing import LITERAL_TYPES, _AnnotationScanType
6
+ from .plugin_loader import PluginLoader # noqa: F401
7
+
8
+
9
+ def _inspect_func_args(fn) -> tuple[list[str], bool]:
10
+ try:
11
+ co_varkeywords = inspect.CO_VARKEYWORDS
12
+ except AttributeError:
13
+ # https://docs.python.org/3/library/inspect.html
14
+ # The flags are specific to CPython, and may not be defined in other
15
+ # Python implementations. Furthermore, the flags are an implementation
16
+ # detail, and can be removed or deprecated in future Python releases.
17
+ spec = inspect.getfullargspec(fn)
18
+ return spec[0], bool(spec[2])
19
+ else:
20
+ # use fn.__code__ plus flags to reduce method call overhead
21
+ co = fn.__code__
22
+ nargs = co.co_argcount
23
+ return (
24
+ list(co.co_varnames[:nargs]),
25
+ bool(co.co_flags & co_varkeywords),
26
+ )
27
+
28
+
29
+ @overload
30
+ def get_cls_kwargs(cls: type, *, _set: Optional[set[str]] = None, raiseerr: Literal[True] = ...) -> set[str]: ...
31
+
32
+
33
+ @overload
34
+ def get_cls_kwargs(cls: type, *, _set: Optional[set[str]] = None, raiseerr: Literal[False] = ...) -> Optional[set[str]]: ...
35
+
36
+
37
+ def get_cls_kwargs(cls: type, *, _set: Optional[set[str]] = None, raiseerr: bool = False) -> Optional[set[str]]:
38
+ """
39
+ Get the keyword arguments for a class constructor.
40
+ Args:
41
+ cls: The class to inspect.
42
+ _set: A set to store the keyword arguments.
43
+ raiseerr: Whether to raise an error if the class is not found.
44
+ Returns:
45
+ A set of keyword arguments for the class constructor.
46
+ """
47
+ toplevel = _set is None
48
+ if toplevel:
49
+ _set = set()
50
+ assert _set is not None
51
+
52
+ ctr = cls.__dict__.get("__init__", False)
53
+
54
+ has_init = ctr and isinstance(ctr, types.FunctionType) and isinstance(ctr.__code__, types.CodeType)
55
+
56
+ if has_init:
57
+ names, has_kw = _inspect_func_args(ctr)
58
+ _set.update(names)
59
+
60
+ if not has_kw and not toplevel:
61
+ if raiseerr:
62
+ raise TypeError(f"given cls {cls} doesn't have an __init__ method")
63
+ else:
64
+ return None
65
+ else:
66
+ has_kw = False
67
+
68
+ if not has_init or has_kw:
69
+ for c in cls.__bases__:
70
+ if get_cls_kwargs(c, _set=_set) is None:
71
+ break
72
+
73
+ _set.discard("self")
74
+ return _set
75
+
76
+
77
+ def avoid_sql_injection(name: str):
78
+ if any(char in name for char in [";", "--", "/*", "*/"]):
79
+ raise ValueError("SQL injection detected")
80
+
81
+
82
+ def is_literal(type_: Any) -> bool:
83
+ return get_origin(type) in LITERAL_TYPES
84
+
85
+
86
+ def is_pep695(type_: _AnnotationScanType) -> TypeGuard[TypeAliasType]:
87
+ return isinstance(type_, TypeAliasType)
@@ -236,7 +236,7 @@ class ModuleTree:
236
236
  # we need to ensure that the object we going to add in table_list is the same
237
237
  for name, obj in table_class:
238
238
  if name == node.class_name:
239
- table_list.append(obj.create_table_query())
239
+ table_list.append(obj.create_table())
240
240
  return tuple(table_list)
241
241
 
242
242
  @staticmethod