ormlambda 3.12.2__py3-none-any.whl → 3.34.1__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 (145) 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/databases/__init__.py +0 -1
  11. ormlambda/databases/my_sql/__init__.py +0 -1
  12. ormlambda/databases/my_sql/caster/caster.py +23 -19
  13. ormlambda/databases/my_sql/caster/types/__init__.py +3 -0
  14. ormlambda/databases/my_sql/caster/types/boolean.py +35 -0
  15. ormlambda/databases/my_sql/caster/types/bytes.py +7 -7
  16. ormlambda/databases/my_sql/caster/types/date.py +34 -0
  17. ormlambda/databases/my_sql/caster/types/datetime.py +7 -7
  18. ormlambda/databases/my_sql/caster/types/decimal.py +32 -0
  19. ormlambda/databases/my_sql/caster/types/float.py +7 -7
  20. ormlambda/databases/my_sql/caster/types/int.py +7 -7
  21. ormlambda/databases/my_sql/caster/types/iterable.py +7 -7
  22. ormlambda/databases/my_sql/caster/types/none.py +8 -7
  23. ormlambda/databases/my_sql/caster/types/point.py +4 -4
  24. ormlambda/databases/my_sql/caster/types/string.py +7 -7
  25. ormlambda/databases/my_sql/clauses/ST_AsText.py +8 -7
  26. ormlambda/databases/my_sql/clauses/ST_Contains.py +10 -5
  27. ormlambda/databases/my_sql/clauses/__init__.py +4 -10
  28. ormlambda/databases/my_sql/clauses/count.py +5 -15
  29. ormlambda/databases/my_sql/clauses/delete.py +3 -50
  30. ormlambda/databases/my_sql/clauses/group_by.py +3 -16
  31. ormlambda/databases/my_sql/clauses/having.py +2 -6
  32. ormlambda/databases/my_sql/clauses/insert.py +4 -92
  33. ormlambda/databases/my_sql/clauses/joins.py +5 -140
  34. ormlambda/databases/my_sql/clauses/limit.py +4 -15
  35. ormlambda/databases/my_sql/clauses/offset.py +4 -15
  36. ormlambda/databases/my_sql/clauses/order.py +4 -61
  37. ormlambda/databases/my_sql/clauses/update.py +4 -67
  38. ormlambda/databases/my_sql/clauses/upsert.py +3 -66
  39. ormlambda/databases/my_sql/clauses/where.py +4 -42
  40. ormlambda/databases/my_sql/repository.py +217 -0
  41. ormlambda/dialects/__init__.py +39 -0
  42. ormlambda/dialects/default/__init__.py +1 -0
  43. ormlambda/dialects/default/base.py +39 -0
  44. ormlambda/dialects/interface/__init__.py +1 -0
  45. ormlambda/dialects/interface/dialect.py +78 -0
  46. ormlambda/dialects/mysql/__init__.py +8 -0
  47. ormlambda/dialects/mysql/base.py +387 -0
  48. ormlambda/dialects/mysql/mysqlconnector.py +46 -0
  49. ormlambda/dialects/mysql/types.py +732 -0
  50. ormlambda/dialects/sqlite/__init__.py +5 -0
  51. ormlambda/dialects/sqlite/base.py +47 -0
  52. ormlambda/dialects/sqlite/pysqlite.py +32 -0
  53. ormlambda/engine/__init__.py +1 -0
  54. ormlambda/engine/base.py +58 -0
  55. ormlambda/engine/create.py +9 -23
  56. ormlambda/engine/url.py +31 -19
  57. ormlambda/env.py +30 -0
  58. ormlambda/errors.py +17 -0
  59. ormlambda/model/base_model.py +7 -9
  60. ormlambda/repository/base_repository.py +36 -5
  61. ormlambda/repository/interfaces/IRepositoryBase.py +121 -7
  62. ormlambda/repository/response.py +134 -0
  63. ormlambda/sql/clause_info/aggregate_function_base.py +19 -9
  64. ormlambda/sql/clause_info/clause_info.py +34 -17
  65. ormlambda/sql/clauses/__init__.py +14 -0
  66. ormlambda/{databases/my_sql → sql}/clauses/alias.py +23 -6
  67. ormlambda/sql/clauses/count.py +57 -0
  68. ormlambda/sql/clauses/delete.py +71 -0
  69. ormlambda/sql/clauses/group_by.py +30 -0
  70. ormlambda/sql/clauses/having.py +21 -0
  71. ormlambda/sql/clauses/insert.py +104 -0
  72. ormlambda/sql/clauses/interfaces/__init__.py +5 -0
  73. ormlambda/{components → sql/clauses}/join/join_context.py +15 -7
  74. ormlambda/sql/clauses/joins.py +159 -0
  75. ormlambda/sql/clauses/limit.py +15 -0
  76. ormlambda/sql/clauses/offset.py +15 -0
  77. ormlambda/sql/clauses/order.py +55 -0
  78. ormlambda/{databases/my_sql → sql}/clauses/select.py +12 -13
  79. ormlambda/sql/clauses/update.py +84 -0
  80. ormlambda/sql/clauses/upsert.py +77 -0
  81. ormlambda/sql/clauses/where.py +65 -0
  82. ormlambda/sql/column/__init__.py +1 -0
  83. ormlambda/sql/{column.py → column/column.py} +82 -22
  84. ormlambda/sql/comparer.py +51 -37
  85. ormlambda/sql/compiler.py +427 -0
  86. ormlambda/sql/ddl.py +68 -0
  87. ormlambda/sql/elements.py +36 -0
  88. ormlambda/sql/foreign_key.py +43 -39
  89. ormlambda/{databases/my_sql → sql}/functions/concat.py +13 -5
  90. ormlambda/{databases/my_sql → sql}/functions/max.py +9 -4
  91. ormlambda/{databases/my_sql → sql}/functions/min.py +9 -13
  92. ormlambda/{databases/my_sql → sql}/functions/sum.py +8 -10
  93. ormlambda/sql/sqltypes.py +647 -0
  94. ormlambda/sql/table/__init__.py +1 -1
  95. ormlambda/sql/table/table.py +179 -0
  96. ormlambda/sql/table/table_constructor.py +1 -208
  97. ormlambda/sql/type_api.py +35 -0
  98. ormlambda/sql/types.py +3 -1
  99. ormlambda/sql/visitors.py +74 -0
  100. ormlambda/statements/__init__.py +1 -0
  101. ormlambda/statements/base_statement.py +28 -38
  102. ormlambda/statements/interfaces/IStatements.py +5 -4
  103. ormlambda/{databases/my_sql → statements}/query_builder.py +35 -30
  104. ormlambda/{databases/my_sql → statements}/statements.py +50 -60
  105. ormlambda/statements/types.py +2 -2
  106. ormlambda/types/__init__.py +24 -0
  107. ormlambda/types/metadata.py +42 -0
  108. ormlambda/util/__init__.py +88 -0
  109. ormlambda/util/load_module.py +21 -0
  110. ormlambda/util/plugin_loader.py +32 -0
  111. ormlambda/util/typing.py +6 -0
  112. ormlambda-3.34.1.dist-info/AUTHORS +32 -0
  113. {ormlambda-3.12.2.dist-info → ormlambda-3.34.1.dist-info}/METADATA +2 -3
  114. ormlambda-3.34.1.dist-info/RECORD +157 -0
  115. {ormlambda-3.12.2.dist-info → ormlambda-3.34.1.dist-info}/WHEEL +1 -1
  116. ormlambda/components/__init__.py +0 -4
  117. ormlambda/components/delete/__init__.py +0 -2
  118. ormlambda/components/delete/abstract_delete.py +0 -17
  119. ormlambda/components/insert/__init__.py +0 -2
  120. ormlambda/components/insert/abstract_insert.py +0 -25
  121. ormlambda/components/select/__init__.py +0 -1
  122. ormlambda/components/update/__init__.py +0 -2
  123. ormlambda/components/update/abstract_update.py +0 -29
  124. ormlambda/components/upsert/__init__.py +0 -2
  125. ormlambda/components/upsert/abstract_upsert.py +0 -25
  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/repository/__init__.py +0 -1
  129. ormlambda/databases/my_sql/repository/repository.py +0 -351
  130. ormlambda/engine/template.py +0 -47
  131. ormlambda/sql/dtypes.py +0 -94
  132. ormlambda/utils/__init__.py +0 -1
  133. ormlambda-3.12.2.dist-info/RECORD +0 -125
  134. /ormlambda/databases/my_sql/{types.py → pool_types.py} +0 -0
  135. /ormlambda/{components/delete → sql/clauses/interfaces}/IDelete.py +0 -0
  136. /ormlambda/{components/insert → sql/clauses/interfaces}/IInsert.py +0 -0
  137. /ormlambda/{components/select → sql/clauses/interfaces}/ISelect.py +0 -0
  138. /ormlambda/{components/update → sql/clauses/interfaces}/IUpdate.py +0 -0
  139. /ormlambda/{components/upsert → sql/clauses/interfaces}/IUpsert.py +0 -0
  140. /ormlambda/{components → sql/clauses}/join/__init__.py +0 -0
  141. /ormlambda/{databases/my_sql → sql}/functions/__init__.py +0 -0
  142. /ormlambda/{utils → util}/module_tree/__init__.py +0 -0
  143. /ormlambda/{utils → util}/module_tree/dfs_traversal.py +0 -0
  144. /ormlambda/{utils → util}/module_tree/dynamic_module.py +0 -0
  145. {ormlambda-3.12.2.dist-info → ormlambda-3.34.1.dist-info}/LICENSE +0 -0
@@ -1,19 +1,19 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
 
4
4
 
5
5
  class StringCaster[TType](BaseCaster[str, TType]):
6
6
  def __init__(self, value: str, type_value: TType):
7
7
  super().__init__(value, type_value)
8
8
 
9
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
10
- return value
9
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
10
+ return Caster.PLACEHOLDER if value is None else value
11
11
 
12
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
13
- return value
12
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
13
+ return Caster.PLACEHOLDER if value is None else value
14
14
 
15
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
16
- return value
15
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
16
+ return Caster.PLACEHOLDER if value is None else value
17
17
 
18
18
  @property
19
19
  @BaseCaster.return_value_if_exists
@@ -1,7 +1,12 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING
1
3
  from ormlambda.sql.clause_info import AggregateFunctionBase
2
4
  from ormlambda.sql.types import ColumnType, AliasType
3
5
  from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
4
6
 
7
+ if TYPE_CHECKING:
8
+ from ormlambda.dialects import Dialect
9
+
5
10
 
6
11
  class ST_AsText[T, TProp](AggregateFunctionBase[None]):
7
12
  """
@@ -20,16 +25,12 @@ class ST_AsText[T, TProp](AggregateFunctionBase[None]):
20
25
  alias_table: AliasType[ColumnType[TProp]] = None,
21
26
  alias_clause: AliasType[ColumnType[TProp]] = None,
22
27
  context: ClauseContextType = None,
28
+ *,
29
+ dialect: Dialect,
23
30
  ) -> None:
24
31
  default_alias_clause = self.create_alias_from(point) if not alias_clause else alias_clause
25
32
 
26
- super().__init__(
27
- table=point.table,
28
- column=point,
29
- alias_table=alias_table,
30
- alias_clause=default_alias_clause,
31
- context=context,
32
- )
33
+ super().__init__(table=point.table, column=point, alias_table=alias_table, alias_clause=default_alias_clause, context=context, dialect=dialect)
33
34
 
34
35
  @staticmethod
35
36
  def create_alias_from(element: ColumnType[TProp]) -> str:
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  import typing as tp
2
3
 
3
4
  from shapely import Point
@@ -6,6 +7,9 @@ from ormlambda import Column
6
7
  from ormlambda.sql.types import ColumnType, AliasType
7
8
  from ormlambda.sql.clause_info import ClauseInfo, IAggregate
8
9
 
10
+ if tp.TYPE_CHECKING:
11
+ from ormlambda.dialects import Dialect
12
+
9
13
 
10
14
  class ST_Contains(IAggregate):
11
15
  FUNCTION_NAME: str = "ST_Contains"
@@ -16,15 +20,16 @@ class ST_Contains(IAggregate):
16
20
  point: Point,
17
21
  alias_table: tp.Optional[AliasType[ColumnType[TProp]]] = None,
18
22
  alias_clause: tp.Optional[AliasType[ColumnType[TProp]]] = None,
23
+ *,
24
+ dialect: Dialect,
19
25
  ):
20
- self.attr1: ClauseInfo[Point] = ClauseInfo(column.table, column, alias_table)
21
- self.attr2: ClauseInfo[Point] = ClauseInfo[Point](None, point)
26
+ self.attr1: ClauseInfo[Point] = ClauseInfo(column.table, column, alias_table, dialect=dialect)
27
+ self.attr2: ClauseInfo[Point] = ClauseInfo[Point](None, point, dialect=dialect)
22
28
 
23
29
  self._alias_clause: AliasType[ColumnType[TProp]] = alias_clause
24
30
 
25
- @property
26
- def query(self) -> str:
27
- return f"{self.FUNCTION_NAME}({self.attr1.query}, {self.attr2.query})"
31
+ def query(self, dialect: Dialect, **kwargs) -> str:
32
+ return f"{self.FUNCTION_NAME}({self.attr1.query(dialect,**kwargs)}, {self.attr2.query(dialect,**kwargs)})"
28
33
 
29
34
  @property
30
35
  def alias_clause(self) -> tp.Optional[str]:
@@ -1,20 +1,14 @@
1
- from .create_database import CreateDatabase as CreateDatabase
2
- from .create_database import TypeExists as TypeExists
3
- from .delete import DeleteQuery as DeleteQuery
4
- from .drop_database import DropDatabase as DropDatabase
1
+ from .delete import DeleteQuery as Delete
5
2
  from .drop_table import DropTable as DropTable
6
- from .insert import InsertQuery as InsertQuery
3
+ from .insert import InsertQuery as Insert
7
4
  from .joins import JoinSelector as JoinSelector
8
- from .joins import JoinType as JoinType
9
5
  from .limit import Limit as Limit
10
6
  from .offset import Offset as Offset
11
7
  from .order import Order as Order
12
- from .update import UpdateQuery as UpdateQuery
13
- from .upsert import UpsertQuery as UpsertQuery
8
+ from .update import Update as Update
9
+ from .upsert import UpsertQuery as Upsert
14
10
  from .where import Where as Where
15
11
  from .having import Having as Having
16
12
  from .count import Count as Count
17
13
  from .group_by import GroupBy as GroupBy
18
- from .alias import Alias as Alias
19
14
  from .ST_AsText import ST_AsText as ST_AsText
20
- from .select import Select as Select
@@ -1,25 +1,19 @@
1
1
  from __future__ import annotations
2
- from ormlambda.sql.clause_info import AggregateFunctionBase
2
+ from ormlambda.sql.clauses import Count
3
3
  from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
4
4
 
5
5
  from ormlambda.sql.types import AliasType, ColumnType
6
6
 
7
7
  from ormlambda import Table
8
8
 
9
- import typing as tp
9
+ from typing import TYPE_CHECKING
10
10
 
11
- from ormlambda.sql.types import ASTERISK
12
-
13
- if tp.TYPE_CHECKING:
11
+ if TYPE_CHECKING:
14
12
  from ormlambda import Table
15
13
  from ormlambda.sql.types import ColumnType, AliasType, TableType
16
14
 
17
15
 
18
- class Count[T: Table](AggregateFunctionBase[T]):
19
- @staticmethod
20
- def FUNCTION_NAME() -> str:
21
- return "COUNT"
22
-
16
+ class Count[T: Table](Count[T]):
23
17
  def __init__[TProp: Table](
24
18
  self,
25
19
  element: ColumnType[T] | TableType[TProp],
@@ -29,12 +23,8 @@ class Count[T: Table](AggregateFunctionBase[T]):
29
23
  keep_asterisk: bool = True,
30
24
  preserve_context: bool = True,
31
25
  ) -> None:
32
- table = self.extract_table(element)
33
- column = element if self.is_column(element) else ASTERISK
34
-
35
26
  super().__init__(
36
- table=table if (alias_table or (context and table in context._table_context)) else None,
37
- column=column,
27
+ element=element,
38
28
  alias_table=alias_table,
39
29
  alias_clause=alias_clause,
40
30
  context=context,
@@ -1,56 +1,9 @@
1
- from typing import Any, Optional, override, Iterable, TYPE_CHECKING
2
-
3
- if TYPE_CHECKING:
4
- from ormlambda import Column
5
-
6
1
  from ormlambda import Table
7
2
  from ormlambda.repository import IRepositoryBase
8
- from ormlambda.components.delete import DeleteQueryBase
3
+ from ormlambda.sql.clauses import Delete
4
+ from mysql.connector import MySQLConnection
9
5
 
10
6
 
11
- class DeleteQuery[T: Table](DeleteQueryBase[T, IRepositoryBase]):
7
+ class DeleteQuery[T: Table](Delete[T, MySQLConnection]):
12
8
  def __init__(self, model: T, repository: IRepositoryBase) -> None:
13
9
  super().__init__(model, repository)
14
-
15
- @property
16
- def CLAUSE(self) -> str:
17
- return "DELETE"
18
-
19
- @override
20
- def delete(self, instances: T | list[T]) -> None:
21
- col: str = ""
22
- if isinstance(instances, Table):
23
- pk: Optional[Column] = instances.get_pk()
24
- if pk is None:
25
- raise Exception(f"You cannot use 'DELETE' query without set primary key in '{instances.__table_name__}'")
26
- col = pk.column_name
27
- value = str(instances[pk])
28
-
29
- elif isinstance(instances, Iterable):
30
- value: list[Any] = []
31
- for ins in instances:
32
- pk = type(ins).get_pk()
33
- value.append(ins[pk])
34
- col = pk.column_name
35
-
36
- query: str = f"{self.CLAUSE} FROM {self._model.__table_name__} WHERE {col}"
37
- if isinstance(value, str):
38
- query += "= %s"
39
- self._query = query
40
- self._values = [value]
41
- return None
42
-
43
- elif isinstance(value, Iterable):
44
- params = ", ".join(["%s"] * len(value))
45
- query += f" IN ({params})"
46
- self._query = query
47
- self._values = value
48
- return None
49
- else:
50
- raise Exception(f"'{type(value)}' no esperado")
51
-
52
- @override
53
- def execute(self) -> None:
54
- if not self._query:
55
- raise ValueError
56
- return self._repository.execute_with_values(self._query, self._values)
@@ -1,14 +1,9 @@
1
- import typing as tp
2
- from ormlambda import Table
3
- from ormlambda.sql.clause_info import AggregateFunctionBase, ClauseInfoContext
1
+ from ormlambda.sql.clause_info import ClauseInfoContext
2
+ from ormlambda.sql.clauses import GroupBy
4
3
  from ormlambda.sql.types import ColumnType
5
4
 
6
5
 
7
- class GroupBy[T: tp.Type[Table], *Ts, TProp](AggregateFunctionBase):
8
- @classmethod
9
- def FUNCTION_NAME(self) -> str:
10
- return "GROUP BY"
11
-
6
+ class GroupBy(GroupBy):
12
7
  def __init__(
13
8
  self,
14
9
  column: ColumnType,
@@ -16,15 +11,7 @@ class GroupBy[T: tp.Type[Table], *Ts, TProp](AggregateFunctionBase):
16
11
  **kwargs,
17
12
  ):
18
13
  super().__init__(
19
- table=column.table,
20
14
  column=column,
21
- alias_table=None,
22
- alias_clause=None,
23
15
  context=context,
24
16
  **kwargs,
25
17
  )
26
-
27
- @property
28
- def query(self) -> str:
29
- column = self._create_query()
30
- return f"{self.FUNCTION_NAME()} {column}"
@@ -1,16 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
- from .where import Where
3
+ from ormlambda.sql.clauses import Having
4
4
 
5
5
 
6
- class Having(Where):
6
+ class Having(Having):
7
7
  """
8
8
  The purpose of this class is to create 'WHERE' condition queries properly.
9
9
  """
10
10
 
11
11
  def __init__(self, *comparer, restrictive=True, context=None):
12
12
  super().__init__(*comparer, restrictive=restrictive, context=context)
13
-
14
- @staticmethod
15
- def FUNCTION_NAME() -> str:
16
- return "HAVING"
@@ -1,97 +1,9 @@
1
1
  from __future__ import annotations
2
-
3
- from typing import override, Iterable, TYPE_CHECKING
4
-
5
2
  from ormlambda import Table
6
- from ormlambda import Column
7
- from ormlambda.components.insert import InsertQueryBase
8
- from ormlambda.repository import IRepositoryBase
9
- from ormlambda.caster import Caster
10
-
11
- if TYPE_CHECKING:
12
- from ormlambda.databases.my_sql import MySQLRepository
3
+ from ormlambda.sql.clauses import Insert
4
+ from mysql.connector import MySQLConnection
13
5
 
14
6
 
15
- class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase]):
16
- def __init__(self, model: T, repository: MySQLRepository) -> None:
7
+ class InsertQuery[T: Table](Insert[T, MySQLConnection]):
8
+ def __init__(self, model, repository):
17
9
  super().__init__(model, repository)
18
-
19
- @override
20
- @property
21
- def CLAUSE(self) -> str:
22
- return "INSERT INTO"
23
-
24
- @override
25
- def execute(self) -> None:
26
- if not self._query:
27
- raise ValueError
28
- return self._repository.executemany_with_values(self.query, self._values)
29
-
30
- @override
31
- def insert[TProp](self, instances: T | list[T]) -> None:
32
- if not isinstance(instances, Iterable):
33
- instances = (instances,)
34
- valid_cols: list[list[Column[TProp]]] = []
35
- self.__fill_dict_list(valid_cols, instances)
36
-
37
- col_names: list[str] = []
38
- wildcards: list[str] = []
39
- col_values: list[list[str]] = []
40
- for i, cols in enumerate(valid_cols):
41
- col_values.append([])
42
- CASTER = Caster(self._repository)
43
- for col in cols:
44
- clean_data = CASTER.for_column(col, instances[i]) # .resolve(instances[i][col])
45
- if i == 0:
46
- col_names.append(col.column_name)
47
- wildcards.append(clean_data.wildcard_to_insert())
48
- # COMMENT: avoid MySQLWriteCastBase.resolve when using PLACEHOLDERs
49
- col_values[-1].append(clean_data.to_database)
50
-
51
- join_cols = ", ".join(col_names)
52
- unknown_rows = f'({", ".join(wildcards)})' # The number of "%s" must match the dict 'dicc_0' length
53
-
54
- self._values = [tuple(x) for x in col_values]
55
- self._query = f"{self.CLAUSE} {self._model.__table_name__} {f'({join_cols})'} VALUES {unknown_rows}"
56
- return None
57
-
58
- @staticmethod
59
- def __is_valid[TProp](column: Column[TProp], value: TProp) -> bool:
60
- """
61
- We want to delete the column from table when it's specified with an 'AUTO_INCREMENT' or 'AUTO GENERATED ALWAYS AS (__) STORED' statement.
62
-
63
- if the column is auto-generated, it means the database creates the value for that column, so we must deleted it.
64
- if the column is primary key and auto-increment, we should be able to create an object with specific pk value.
65
-
66
- RETURN
67
- -----
68
-
69
- - True -> Do not delete the column from dict query
70
- - False -> Delete the column from dict query
71
- """
72
-
73
- is_pk_none_and_auto_increment: bool = all([value is None, column.is_primary_key, column.is_auto_increment])
74
-
75
- if is_pk_none_and_auto_increment or column.is_auto_generated:
76
- return False
77
- return True
78
-
79
- def __fill_dict_list[TProp](self, list_dict: list[str, TProp], values: list[T]) -> list[Column]:
80
- if isinstance(values, Iterable):
81
- for x in values:
82
- self.__fill_dict_list(list_dict, x)
83
-
84
- elif issubclass(values.__class__, Table):
85
- new_list = []
86
- for prop in type(values).__dict__.values():
87
- if not isinstance(prop, Column):
88
- continue
89
-
90
- value = getattr(values, prop.column_name)
91
- if self.__is_valid(prop, value):
92
- new_list.append(prop)
93
- list_dict.append(new_list)
94
-
95
- else:
96
- raise Exception(f"Tipo de dato'{type(values)}' no esperado")
97
- return None
@@ -1,149 +1,14 @@
1
1
  from __future__ import annotations
2
- from collections import defaultdict
3
- from typing import override, Optional, TYPE_CHECKING, Type
2
+ from typing import TYPE_CHECKING
4
3
 
5
4
 
6
- from ormlambda.utils.module_tree.dfs_traversal import DFSTraversal
7
- from ormlambda.common.interfaces.IJoinSelector import IJoinSelector
8
- from ormlambda.common.interfaces.IQueryCommand import IQuery
9
- from ormlambda import JoinType
10
- from ormlambda.sql.clause_info import ClauseInfo
11
- from ormlambda.sql.comparer import Comparer
12
- from ormlambda.sql.clause_info.clause_info_context import ClauseInfoContext, ClauseContextType
5
+ from ormlambda.sql.clauses import JoinSelector
13
6
 
14
7
  # TODOL [x]: Try to import Table module without circular import Error
15
8
  if TYPE_CHECKING:
16
9
  from ormlambda import Table
17
10
 
18
11
 
19
- class JoinSelector[TLeft: Table, TRight: Table](IJoinSelector[TLeft, TRight]):
20
- __slots__: tuple = (
21
- "_comparer",
22
- "_orig_table",
23
- "_right_table",
24
- "_by",
25
- "_left_col",
26
- "_right_col",
27
- "_compareop",
28
- "_alias",
29
- )
30
-
31
- @override
32
- def __repr__(self) -> str:
33
- table_col_left: str = f"{self.left_table.table_alias()}.{self._left_col}"
34
- table_col_right: str = f"{self.right_table.table_alias()}.{self._right_col}"
35
-
36
- return f"{IQuery.__name__}: {self.__class__.__name__} ({table_col_left} == {table_col_right})"
37
-
38
- def __init__[LProp, RProp](
39
- self,
40
- where: Comparer[TLeft, LProp, TRight, RProp],
41
- by: JoinType,
42
- alias: Optional[str] = "{table}",
43
- context: ClauseContextType = None,
44
- ) -> 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
48
- 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
51
- self._compareop = where._compare
52
- self._context: ClauseContextType = context if context else ClauseInfoContext()
53
-
54
- # COMMENT: When multiple columns reference the same table, we need to create an alias to maintain clear references.
55
- self._alias: Optional[str] = alias
56
-
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())
60
-
61
- def __eq__(self, __value: JoinSelector) -> bool:
62
- return isinstance(__value, JoinSelector) and self.__hash__() == __value.__hash__()
63
-
64
- def __hash__(self) -> int:
65
- return hash(
66
- (
67
- self.left_table,
68
- self.right_table,
69
- self._by,
70
- self._left_col,
71
- self._right_col,
72
- self._compareop,
73
- )
74
- )
75
-
76
- def _create_partial_context(self) -> ClauseInfoContext:
77
- """
78
- Only use table_context from global context
79
- """
80
- if not self._context:
81
- return ClauseInfoContext()
82
- return ClauseInfoContext(clause_context=None, table_context=self._context._table_context)
83
-
84
- @classmethod
85
- def join_selectors(cls, *args: JoinSelector) -> str:
86
- return "\n".join([x.query for x in args])
87
-
88
- @property
89
- @override
90
- def query(self) -> str:
91
- self._context = ClauseInfoContext(clause_context=None, table_context=self._context._table_context)
92
- list_ = [
93
- self._by.value, # inner join
94
- self._from_clause.query,
95
- "ON",
96
- self._left_table_clause.query,
97
- self._compareop, # =
98
- self._right_table_clause.query,
99
- ]
100
- return " ".join([x for x in list_ if x is not None])
101
-
102
- @property
103
- def left_table(self) -> TLeft:
104
- return self._orig_table
105
-
106
- @property
107
- def right_table(self) -> TRight:
108
- return self._right_table
109
-
110
- @property
111
- def left_col(self) -> str:
112
- return self._left_col
113
-
114
- @property
115
- def right_col(self) -> str:
116
- return self._right_col
117
-
118
- @property
119
- def alias(self) -> str:
120
- return self._alias
121
-
122
- @classmethod
123
- def sort_join_selectors(cls, joins: set[JoinSelector]) -> tuple[JoinSelector]:
124
- # FIXME [x]: How to sort when needed because it's not necessary at this point. It is for testing purpouse
125
- if len(joins) == 1:
126
- return tuple(joins)
127
-
128
- join_object_map: dict[str, list[JoinSelector]] = defaultdict(list)
129
-
130
- for obj in joins:
131
- join_object_map[obj.left_table].append(obj)
132
-
133
- graph: dict[Type[Table], list[Type[Table]]] = defaultdict(list)
134
- for join in joins:
135
- graph[join.left_table].append(join.right_table)
136
-
137
- sorted_graph = DFSTraversal.sort(graph)[::-1]
138
-
139
- if not sorted_graph:
140
- return tuple(joins)
141
-
142
- res = []
143
- for table in sorted_graph:
144
- tables = join_object_map[table]
145
-
146
- if not tables:
147
- continue
148
- res.extend(tables)
149
- return res
12
+ class JoinSelector[TLeft: Table, TRight: Table](JoinSelector[TLeft, TRight]):
13
+ def __init__(self, where, by, alias="{table}", context=None, **kw):
14
+ super().__init__(where, by, alias, context, **kw)
@@ -1,17 +1,6 @@
1
- from typing import override
1
+ from ormlambda.sql.clauses import Limit
2
2
 
3
- from ormlambda.common.interfaces.IQueryCommand import IQuery
4
3
 
5
-
6
- class Limit(IQuery):
7
- LIMIT = "LIMIT"
8
-
9
- def __init__(self, number: int) -> None:
10
- if not isinstance(number, int):
11
- raise ValueError
12
- self._number: int = number
13
-
14
- @override
15
- @property
16
- def query(self) -> str:
17
- return f"{self.LIMIT} {self._number}"
4
+ class Limit(Limit):
5
+ def __init__(self, number):
6
+ super().__init__(number)
@@ -1,17 +1,6 @@
1
- from typing import override
1
+ from ormlambda.sql.clauses import Offset
2
2
 
3
- from ormlambda.common.interfaces.IQueryCommand import IQuery
4
3
 
5
-
6
- class Offset(IQuery):
7
- OFFSET = "OFFSET"
8
-
9
- def __init__(self, number: int) -> None:
10
- if not isinstance(number, int):
11
- raise ValueError
12
- self._number: int = number
13
-
14
- @override
15
- @property
16
- def query(self) -> str:
17
- return f"{self.OFFSET} {self._number}"
4
+ class Offset(Offset):
5
+ def __init__(self, number):
6
+ super().__init__(number)
@@ -1,65 +1,8 @@
1
1
  from __future__ import annotations
2
- import typing as tp
3
2
 
4
- from ormlambda.sql.clause_info.clause_info_context import ClauseInfoContext, ClauseContextType
5
- from ormlambda.sql.types import ColumnType
6
- from ormlambda.sql.clause_info import AggregateFunctionBase
3
+ from ormlambda.sql.clauses import Order
7
4
 
8
- from ormlambda.statements import OrderType
9
5
 
10
-
11
- class Order(AggregateFunctionBase):
12
- @staticmethod
13
- def FUNCTION_NAME() -> str:
14
- return "ORDER BY"
15
-
16
- def __init__[TProp](
17
- self,
18
- column: tuple[ColumnType[TProp], ...] | ColumnType[TProp],
19
- order_type: tp.Iterable[OrderType],
20
- context: ClauseContextType = None,
21
- ):
22
- super().__init__(
23
- table=None,
24
- column=column,
25
- context=context,
26
- )
27
-
28
- if isinstance(order_type, str) or not isinstance(order_type, tp.Iterable):
29
- order_type = (order_type,)
30
-
31
- self._order_type: list[OrderType] = [self.__cast_to_OrderType(x) for x in order_type]
32
-
33
- def __cast_to_OrderType(self, _value: tp.Any) -> tp.Iterable[OrderType]:
34
- if isinstance(_value, OrderType):
35
- return _value
36
-
37
- if isinstance(_value, str):
38
- try:
39
- return OrderType(_value)
40
- except Exception:
41
- pass
42
- raise Exception(f"order_type param only can be 'ASC' or 'DESC' string or '{OrderType.__name__}' enum")
43
-
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)}"
6
+ class Order(Order):
7
+ def __init__(self, column, order_type, context=None):
8
+ super().__init__(column, order_type, context)