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,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]:
@@ -0,0 +1,13 @@
1
+ from .delete import DeleteQuery as Delete
2
+ from .insert import InsertQuery as Insert
3
+ from .joins import JoinSelector as JoinSelector
4
+ from .limit import Limit as Limit
5
+ from .offset import Offset as Offset
6
+ from .order import Order as Order
7
+ from .update import Update as Update
8
+ from .upsert import UpsertQuery as Upsert
9
+ from .where import Where as Where
10
+ from .having import Having as Having
11
+ from .count import Count as Count
12
+ from .group_by import GroupBy as GroupBy
13
+ from .ST_AsText import ST_AsText as ST_AsText
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+ from ormlambda.sql.clauses import Count
3
+ from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
4
+
5
+ from ormlambda.sql.types import AliasType, ColumnType
6
+
7
+ from ormlambda import Table
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from ormlambda import Table
13
+ from ormlambda.sql.types import ColumnType, AliasType, TableType
14
+
15
+
16
+ class Count[T: Table](Count[T]):
17
+ def __init__[TProp: Table](
18
+ self,
19
+ element: ColumnType[T] | TableType[TProp],
20
+ alias_table: AliasType[ColumnType[TProp]] = None,
21
+ alias_clause: AliasType[ColumnType[TProp]] = "count",
22
+ context: ClauseContextType = None,
23
+ keep_asterisk: bool = True,
24
+ preserve_context: bool = True,
25
+ ) -> None:
26
+ super().__init__(
27
+ element=element,
28
+ alias_table=alias_table,
29
+ alias_clause=alias_clause,
30
+ context=context,
31
+ keep_asterisk=keep_asterisk,
32
+ preserve_context=preserve_context,
33
+ )
@@ -0,0 +1,9 @@
1
+ from ormlambda import Table
2
+ from ormlambda.repository import IRepositoryBase
3
+ from ormlambda.sql.clauses import Delete
4
+ from mysql.connector import MySQLConnection
5
+
6
+
7
+ class DeleteQuery[T: Table](Delete[T, MySQLConnection]):
8
+ def __init__(self, model: T, repository: IRepositoryBase) -> None:
9
+ super().__init__(model, repository)
@@ -0,0 +1,17 @@
1
+ from ormlambda.sql.clause_info import ClauseInfoContext
2
+ from ormlambda.sql.clauses import GroupBy
3
+ from ormlambda.sql.types import ColumnType
4
+
5
+
6
+ class GroupBy(GroupBy):
7
+ def __init__(
8
+ self,
9
+ column: ColumnType,
10
+ context: ClauseInfoContext,
11
+ **kwargs,
12
+ ):
13
+ super().__init__(
14
+ column=column,
15
+ context=context,
16
+ **kwargs,
17
+ )
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from ormlambda.sql.clauses import Having
4
+
5
+
6
+ class Having(Having):
7
+ """
8
+ The purpose of this class is to create 'WHERE' condition queries properly.
9
+ """
10
+
11
+ def __init__(self, *comparer, restrictive=True, context=None):
12
+ super().__init__(*comparer, restrictive=restrictive, context=context)
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+ from ormlambda import Table
3
+ from ormlambda.sql.clauses import Insert
4
+ from mysql.connector import MySQLConnection
5
+
6
+
7
+ class InsertQuery[T: Table](Insert[T, MySQLConnection]):
8
+ def __init__(self, model, repository):
9
+ super().__init__(model, repository)
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING
3
+
4
+
5
+ from ormlambda.sql.clauses import JoinSelector
6
+
7
+ # TODOL [x]: Try to import Table module without circular import Error
8
+ if TYPE_CHECKING:
9
+ from ormlambda import Table
10
+
11
+
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)
@@ -0,0 +1,6 @@
1
+ from ormlambda.sql.clauses import Limit
2
+
3
+
4
+ class Limit(Limit):
5
+ def __init__(self, number):
6
+ super().__init__(number)
@@ -0,0 +1,6 @@
1
+ from ormlambda.sql.clauses import Offset
2
+
3
+
4
+ class Offset(Offset):
5
+ def __init__(self, number):
6
+ super().__init__(number)
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ from ormlambda.sql.clauses import Order
4
+
5
+
6
+ class Order(Order):
7
+ def __init__(self, column, order_type, context=None):
8
+ super().__init__(column, order_type, context)
@@ -0,0 +1,8 @@
1
+ from mysql.connector import MySQLConnection
2
+
3
+ from ormlambda.sql.clauses import Update
4
+
5
+
6
+ class Update[T](Update[T, MySQLConnection]):
7
+ def __init__(self, model, repository, where):
8
+ super().__init__(model, repository, where)
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ from ormlambda import Table
4
+ from ormlambda.sql.clauses.upsert import Upsert
5
+
6
+
7
+ class UpsertQuery[T: Table](Upsert):
8
+ def __init__(self, model, repository):
9
+ super().__init__(model, repository)
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+ from ormlambda.sql.clauses import Where
3
+
4
+
5
+ class Where(Where):
6
+ def __init__(self, *comparer, restrictive=True, context=None):
7
+ super().__init__(*comparer, restrictive=restrictive, context=context)
@@ -0,0 +1,46 @@
1
+ # dialects/mysql/mysqlconnector.py
2
+ # Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+ # mypy: ignore-errors
8
+
9
+ r"""
10
+ .. dialect:: mysql+mysqlconnector
11
+ :name: MySQL Connector/Python
12
+ :dbapi: myconnpy
13
+ :connectstring: mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
14
+ :url: https://pypi.org/project/mysql-connector-python/
15
+
16
+ .. note::
17
+
18
+ The MySQL Connector/Python DBAPI has had many issues since its release,
19
+ some of which may remain unresolved, and the mysqlconnector dialect is
20
+ The recommended MySQL dialects are mysqlclient and PyMySQL.
21
+
22
+ """ # noqa
23
+
24
+ from __future__ import annotations
25
+ from types import ModuleType
26
+ from .base import MySQLCompiler
27
+ from .base import MySQLDialect
28
+
29
+
30
+ class MySQLCompiler_mysqlconnector(MySQLCompiler):
31
+ def visit_mod_binary(self, binary, operator, **kw):
32
+ return self.process(binary.left, **kw) + " % " + self.process(binary.right, **kw)
33
+
34
+
35
+ class MySQLDialect_mysqlconnector(MySQLDialect):
36
+ driver = "mysqlconnector"
37
+ statement_compiler = MySQLCompiler_mysqlconnector
38
+
39
+ @classmethod
40
+ def import_dbapi(cls) -> ModuleType:
41
+ from mysql import connector
42
+
43
+ return connector
44
+
45
+
46
+ dialect = MySQLDialect_mysqlconnector
@@ -0,0 +1 @@
1
+ from .repository import MySQLRepository
@@ -0,0 +1,212 @@
1
+ from __future__ import annotations
2
+ import contextlib
3
+ from pathlib import Path
4
+ from typing import Generator, Iterable, Optional, Type, override, TYPE_CHECKING, Unpack
5
+ import uuid
6
+
7
+ # from mysql.connector.pooling import MySQLConnectionPool
8
+ from mysql.connector import MySQLConnection # noqa: F401
9
+ from mysql.connector.pooling import MySQLConnectionPool # noqa: F401
10
+ from ormlambda.repository import BaseRepository
11
+
12
+ # Custom libraries
13
+ from ormlambda.repository.response import Response
14
+ from ormlambda.caster import Caster
15
+
16
+ if TYPE_CHECKING:
17
+ from ormlambda import URL as _URL
18
+ from ormlambda.sql.clauses import Select
19
+ from .pool_types import MySQLArgs
20
+
21
+
22
+ class MySQLRepository(BaseRepository[MySQLConnectionPool]):
23
+ # def get_connection[**P, TReturn](func: Callable[Concatenate[MySQLRepository, MySQLConnection, P], TReturn]) -> Callable[P, TReturn]:
24
+ # def wrapper(self: MySQLRepository, *args: P.args, **kwargs: P.kwargs):
25
+ # with self.get_connection() as cnx:
26
+ # try:
27
+ # return func(self, cnx._cnx, *args, **kwargs)
28
+ # except Exception as e:
29
+ # cnx._cnx.rollback()
30
+ # raise e
31
+
32
+ # return wrapper
33
+
34
+ #
35
+
36
+ def __init__(
37
+ self,
38
+ /,
39
+ url: Optional[_URL] = None,
40
+ *,
41
+ user: Optional[str] = None,
42
+ password: Optional[str] = None,
43
+ host: Optional[str] = None,
44
+ database: Optional[str] = None,
45
+ **kwargs: Unpack[MySQLArgs],
46
+ ):
47
+ timeout = self.__add_connection_timeout(kwargs)
48
+ name = self.__add_pool_name(kwargs)
49
+ size = self.__add_pool_size(kwargs)
50
+ attr = kwargs.copy()
51
+ attr["connection_timeout"] = timeout
52
+ attr["pool_name"] = name
53
+ attr["pool_size"] = size
54
+
55
+ super().__init__(
56
+ user=user if not url else url.username,
57
+ password=password if not url else url.password,
58
+ host=host if not url else url.host,
59
+ database=database if not url else url.database,
60
+ pool=MySQLConnectionPool,
61
+ **attr,
62
+ )
63
+
64
+ @staticmethod
65
+ def __add_connection_timeout(kwargs: MySQLArgs) -> int:
66
+ if "connection_timeout" not in kwargs.keys():
67
+ return 60
68
+ return int(kwargs.pop("connection_timeout"))
69
+
70
+ @staticmethod
71
+ def __add_pool_name(kwargs: MySQLArgs) -> str:
72
+ if "pool_name" not in kwargs.keys():
73
+ return str(uuid.uuid4())
74
+
75
+ return kwargs.pop("pool_name")
76
+
77
+ @staticmethod
78
+ def __add_pool_size(kwargs: MySQLArgs) -> int:
79
+ if "pool_size" not in kwargs.keys():
80
+ return 5
81
+ return int(kwargs.pop("pool_size"))
82
+
83
+ @contextlib.contextmanager
84
+ def get_connection(self) -> Generator[MySQLConnection, None, None]:
85
+ with self._pool.get_connection() as cnx:
86
+ try:
87
+ yield cnx._cnx
88
+ cnx._cnx.commit()
89
+ except Exception as exc:
90
+ cnx._cnx.rollback()
91
+ raise exc
92
+
93
+ @override
94
+ def read_sql[TFlavour: Iterable](
95
+ self,
96
+ query: str,
97
+ flavour: tuple | Type[TFlavour] = tuple,
98
+ **kwargs,
99
+ ) -> tuple[TFlavour]:
100
+ """
101
+ Return tuple of tuples by default.
102
+
103
+ ATTRIBUTE
104
+ -
105
+ - query:str: string of request to the server
106
+ - flavour: Type[TFlavour]: Useful to return tuple of any Iterable type as dict,set,list...
107
+ """
108
+
109
+ select: Select = kwargs.pop("select", None)
110
+
111
+ with self.get_connection() as cnx:
112
+ with cnx.cursor(buffered=True) as cursor:
113
+ cursor.execute(query)
114
+ values: list[tuple] = cursor.fetchall()
115
+ columns: tuple[str] = cursor.column_names
116
+ return Response(
117
+ dialect=self._dialect,
118
+ response_values=values,
119
+ columns=columns,
120
+ flavour=flavour,
121
+ select=select,
122
+ ).response(**kwargs)
123
+
124
+ # FIXME [ ]: this method does not comply with the implemented interface
125
+ def create_tables_code_first(self, path: str | Path) -> None:
126
+ return
127
+ from ormlambda.utils.module_tree.dynamic_module import ModuleTree
128
+
129
+ if not isinstance(path, Path | str):
130
+ raise ValueError
131
+
132
+ if isinstance(path, str):
133
+ path = Path(path).resolve()
134
+
135
+ if not path.exists():
136
+ raise FileNotFoundError
137
+
138
+ module_tree: ModuleTree = ModuleTree(path)
139
+
140
+ queries_list: list[str] = module_tree.get_queries()
141
+
142
+ for query in queries_list:
143
+ with self.get_connection() as cnx:
144
+ with cnx.cursor(buffered=True) as cursor:
145
+ cursor.execute(query)
146
+ return None
147
+
148
+ @override
149
+ def executemany_with_values(self, query: str, values) -> None:
150
+ with self.get_connection() as cnx:
151
+ with cnx.cursor(buffered=True) as cursor:
152
+ cursor.executemany(query, values)
153
+ return None
154
+
155
+ @override
156
+ def execute_with_values(self, query: str, values) -> None:
157
+ with self.get_connection() as cnx:
158
+ with cnx.cursor(buffered=True) as cursor:
159
+ cursor.execute(query, values)
160
+ return None
161
+
162
+ @override
163
+ def execute(self, query: str) -> None:
164
+ with self.get_connection() as cnx:
165
+ with cnx.cursor(buffered=True) as cursor:
166
+ cursor.execute(query)
167
+ return None
168
+
169
+ @override
170
+ def database_exists(self, name: str) -> bool:
171
+ temp_config = self._pool._cnx_config
172
+
173
+ config_without_db = temp_config.copy()
174
+
175
+ if "database" in config_without_db:
176
+ config_without_db.pop("database")
177
+ self._pool.set_config(**config_without_db)
178
+
179
+ with self.get_connection() as cnx:
180
+ with cnx.cursor(buffered=True) as cursor:
181
+ cursor.execute(f"SHOW DATABASES LIKE {Caster.PLACEHOLDER};", (name,))
182
+ res = cursor.fetchmany(1)
183
+
184
+ self._pool.set_config(**temp_config)
185
+ return len(res) > 0
186
+
187
+ @override
188
+ def table_exists(self, name: str) -> bool:
189
+ with self.get_connection() as cnx:
190
+ if not cnx.database:
191
+ raise Exception("No database selected")
192
+ with cnx.cursor(buffered=True) as cursor:
193
+ cursor.execute(f"SHOW TABLES LIKE {Caster.PLACEHOLDER};", (name,))
194
+ res = cursor.fetchmany(1)
195
+ return len(res) > 0
196
+
197
+ @property
198
+ def database(self) -> Optional[str]:
199
+ return self._pool._cnx_config.get("database", None)
200
+
201
+ @database.setter
202
+ def database(self, value: str) -> None:
203
+ """Change the current database using USE statement"""
204
+
205
+ if not self.database_exists(value):
206
+ raise ValueError(f"You cannot set the non-existent '{value}' database.")
207
+
208
+ old_config: MySQLArgs = self._pool._cnx_config.copy()
209
+ old_config["database"] = value
210
+
211
+ self._pool._remove_connections()
212
+ self._pool = type(self)(**old_config)._pool