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
ormlambda/__init__.py CHANGED
@@ -1,3 +1,5 @@
1
+ import ormlambda.env # noqa: F401 Necesary to load all variables inside ormalambda.env
2
+
1
3
  # region enums
2
4
  from .common.enums import (
3
5
  JoinType as JoinType,
@@ -1,3 +1,3 @@
1
1
  from .base_caster import BaseCaster # noqa: F401
2
- from .caster import Caster, PLACEHOLDER # noqa: F401
2
+ from .caster import Caster # noqa: F401
3
3
  from .interfaces import ICaster # noqa: F401
@@ -1,24 +1,26 @@
1
1
  from __future__ import annotations
2
2
 
3
3
 
4
- from typing import Optional, Type, TYPE_CHECKING, Callable, overload
5
-
4
+ from typing import ClassVar, Optional, Type, TYPE_CHECKING, Callable, overload, get_args
5
+ from types import NoneType
6
+ from ormlambda.caster.interfaces import ICaster
6
7
  from ormlambda.common.global_checker import GlobalChecker
7
8
  from ormlambda.sql.types import ColumnType
8
- from ormlambda.engine.template import RepositoryTemplateDict
9
+ from ormlambda.caster import BaseCaster
10
+ from ormlambda.sql.sqltypes import TypeEngine
11
+
9
12
 
10
13
  if TYPE_CHECKING:
11
14
  from ormlambda.caster import BaseCaster
12
- from ormlambda.repository import IRepositoryBase
13
15
 
14
16
 
15
- PLACEHOLDER: str = "%s"
17
+ class Caster(ICaster):
18
+ PLACEHOLDER: ClassVar[str] = "%s"
16
19
 
17
-
18
- class Caster:
19
- def __init__(self, repository: IRepositoryBase):
20
- self._repository: IRepositoryBase = repository
21
- self._caster = RepositoryTemplateDict().get(repository).caster
20
+ @classmethod
21
+ def set_placeholder(cls, char: str) -> None:
22
+ cls.PLACEHOLDER = char
23
+ return None
22
24
 
23
25
  @overload
24
26
  def for_column[T, TProp](self, column: Callable[[T], TProp], instance: T) -> BaseCaster[TProp, Type[TProp]]: ...
@@ -36,7 +38,7 @@ class Caster:
36
38
  column_type = column.dtype
37
39
  value = instance[column]
38
40
 
39
- return self._caster.cast(value, column_type)
41
+ return self.cast(value, column_type)
40
42
 
41
43
  @overload
42
44
  def for_value[TProp](self, value: TProp) -> BaseCaster[TProp, Type[TProp]]: ...
@@ -45,4 +47,19 @@ class Caster:
45
47
 
46
48
  def for_value[TProp, TType](self, value: TProp, value_type: Optional[TType] = None) -> BaseCaster[TProp, TType]:
47
49
  column_type = value_type if value_type else type(value)
48
- return self._caster.cast(value, column_type)
50
+ return self.cast(value, column_type)
51
+
52
+ @classmethod
53
+ def cast[TProp, TType](cls, value: TProp, type_value: Optional[TypeEngine[TType]] = None) -> BaseCaster[TProp, TType]:
54
+ if len(args := get_args(type_value)) > 1:
55
+ args = [x for x in args if x != NoneType]
56
+
57
+ type_value = args[0]
58
+
59
+ if isinstance(type_value, TypeEngine):
60
+ column_type = type_value.python_type
61
+ elif not type_value:
62
+ column_type = type(value)
63
+ else:
64
+ column_type = type_value
65
+ return cls.CASTER_SELECTOR()[column_type](value, column_type)
@@ -17,21 +17,13 @@ class ClauseInfoConverter[T, TProp](tp.Protocol):
17
17
  class ConvertFromAnyType(ClauseInfoConverter[None, None]):
18
18
  @classmethod
19
19
  def convert(cls, data: tp.Any, alias_table: AliasType = "{table}", context: ClauseContextType = None, **kwargs) -> list[ClauseInfo[None]]:
20
- return [
21
- ClauseInfo[None](
22
- table=None,
23
- column=data,
24
- alias_table=alias_table,
25
- alias_clause=kwargs.get("alias", None),
26
- context=context,
27
- )
28
- ]
20
+ return [ClauseInfo[None](table=None, column=data, alias_table=alias_table, alias_clause=kwargs.get("alias", None), context=context, **kwargs)]
29
21
 
30
22
 
31
23
  class ConvertFromForeignKey[LT: Table, RT: Table](ClauseInfoConverter[RT, None]):
32
24
  @classmethod
33
25
  def convert(cls, data: ForeignKey[LT, RT], alias_table=None, context: ClauseContextType = None, **kwargs) -> list[ClauseInfo[RT]]:
34
- return ConvertFromTable[RT].convert(data.tright, data.alias, context, **kwargs)
26
+ return ConvertFromTable[RT].convert(data.tright, data.get_alias(kwargs["dialect"]), context, **kwargs)
35
27
 
36
28
 
37
29
  class ConvertFromColumn[TProp](ClauseInfoConverter[None, TProp]):
@@ -44,9 +36,9 @@ class ConvertFromColumn[TProp](ClauseInfoConverter[None, TProp]):
44
36
  "alias_table": alias_table,
45
37
  "alias_clause": "{table}_{column}",
46
38
  "context": context,
47
- **kwargs,
48
39
  }
49
- clause_info = ClauseInfo[None](**attributes)
40
+ attributes.update(**kwargs)
41
+ clause_info = ClauseInfo(**attributes)
50
42
  return [clause_info]
51
43
 
52
44
 
@@ -27,6 +27,9 @@ type ValueType = tp.Union[
27
27
  tp.Type[ICustomAlias],
28
28
  ]
29
29
 
30
+ if tp.TYPE_CHECKING:
31
+ from ormlambda.dialects import Dialect
32
+
30
33
 
31
34
  class DecompositionQueryBase[T: Table, *Ts](IDecompositionQuery[T, *Ts]):
32
35
  @tp.overload
@@ -36,10 +39,20 @@ class DecompositionQueryBase[T: Table, *Ts](IDecompositionQuery[T, *Ts]):
36
39
  @tp.overload
37
40
  def __init__(self, tables: tuple[TableType[T]], columns: tuple[ColumnType], alias_table: str, context: ClauseContextType = ...) -> None: ...
38
41
 
39
- def __init__(self, tables: tuple[TableType[T]], columns: tuple[ColumnType], alias_table: str = "{table}", *, context: ClauseContextType = ClauseInfoContext(), **kwargs) -> None:
42
+ def __init__(
43
+ self,
44
+ tables: tuple[TableType[T]],
45
+ columns: tuple[ColumnType],
46
+ alias_table: str = "{table}",
47
+ *,
48
+ context: ClauseContextType = ClauseInfoContext(),
49
+ dialect: Dialect,
50
+ **kwargs,
51
+ ) -> None:
40
52
  self.kwargs = kwargs
41
53
  self._tables: tuple[TableType[T]] = tables if isinstance(tables, tp.Iterable) else (tables,)
42
54
 
55
+ self._dialect = dialect
43
56
  self._columns: tp.Callable[[T], tuple] = columns
44
57
  self._all_clauses: list[ClauseInfo | AggregateFunctionBase] = []
45
58
  self._context: ClauseContextType = context if context else ClauseInfoContext()
@@ -88,7 +101,9 @@ class DecompositionQueryBase[T: Table, *Ts](IDecompositionQuery[T, *Ts]):
88
101
  Table: ConvertFromTable[T],
89
102
  }
90
103
  classConverter = next((converter for obj, converter in VALUE_TYPE_MAPPED.items() if validation(data, obj)), ConvertFromAnyType)
91
-
104
+ self.kwargs.setdefault("dialect", self._dialect)
105
+ if "dialect" not in self.kwargs:
106
+ raise ValueError("You must specified 'dialect' variable")
92
107
  return classConverter.convert(data, alias_table=self._alias_table, context=self._context, **self.kwargs)
93
108
 
94
109
  def __add_clause[TTable: TableType](self, clauses: list[ClauseInfo[TTable]] | ClauseInfo[TTable]) -> None:
@@ -1,22 +1,26 @@
1
1
  from __future__ import annotations
2
2
  from abc import abstractmethod
3
- from typing import Any, Optional, Type, override, TYPE_CHECKING
3
+ from typing import Any, Optional, Type, TYPE_CHECKING
4
4
 
5
5
  from ormlambda.common.interfaces.INonQueryCommand import INonQueryCommand
6
6
 
7
7
  if TYPE_CHECKING:
8
8
  from ormlambda.repository import BaseRepository
9
+ from ormlambda.dialects import Dialect
9
10
  from ormlambda import Table
11
+ from ormlambda.engine import Engine
10
12
 
11
13
 
12
- class NonQueryBase[T: Type[Table], TRepo: BaseRepository](INonQueryCommand):
14
+ class NonQueryBase[T: Type[Table], TRepo](INonQueryCommand):
13
15
  __slots__: tuple[str, ...] = ("_model", "_repository", "_values", "_query")
14
16
 
15
- def __init__(self, model: T, repository: TRepo) -> None:
17
+ def __init__(self, model: T, repository: TRepo, **kwargs) -> None:
16
18
  self._model: T = model
17
- self._repository: TRepo = repository
19
+ self._repository: BaseRepository[TRepo] = repository
18
20
  self._values: list[tuple[Any]] = []
19
21
  self._query: Optional[str] = None
22
+ self._dialect: Dialect = kwargs.get("dialect", None)
23
+ self._engine: Optional[Engine] = kwargs.get("engine", None)
20
24
 
21
25
  @property
22
26
  @abstractmethod
@@ -25,9 +29,7 @@ class NonQueryBase[T: Type[Table], TRepo: BaseRepository](INonQueryCommand):
25
29
  @abstractmethod
26
30
  def execute(self) -> None: ...
27
31
 
28
- @property
29
- @override
30
- def query(self) -> str:
32
+ def query(self, dialect: Dialect, **kwargs) -> str:
31
33
  return self._query
32
34
 
33
35
  @property
@@ -1,3 +1,4 @@
1
+ from __future__ import annotations
1
2
  from abc import abstractmethod
2
3
  from typing import TYPE_CHECKING
3
4
 
@@ -5,9 +6,10 @@ from ormlambda.common.interfaces import IQuery
5
6
 
6
7
  if TYPE_CHECKING:
7
8
  from ormlambda import Table
9
+ from ormlambda.dialects import Dialect
8
10
 
9
11
 
10
12
  class QueryBase[T: Table](IQuery):
11
13
  @property
12
14
  @abstractmethod
13
- def query(self) -> str: ...
15
+ def query(self, dialect: Dialect, **kwargs) -> str: ...
@@ -1,7 +1,12 @@
1
+ from __future__ import annotations
1
2
  import inspect
2
3
  import typing as tp
3
4
 
4
5
 
6
+ if tp.TYPE_CHECKING:
7
+ from ormlambda.sql.clause_info import ClauseInfo
8
+
9
+
5
10
  class UnmatchedLambdaParameterError(Exception):
6
11
  def __init__(self, expected_params: int, function: tp.Callable[..., tp.Any], *args: object) -> None:
7
12
  super().__init__(*args)
@@ -19,3 +24,27 @@ class NotKeysInIAggregateError(Exception):
19
24
 
20
25
  def __str__(self) -> str:
21
26
  return f"We cannot use placeholders in IAggregate class. You used {self._match_regex}"
27
+
28
+
29
+ class AggregateFunctionError[T](Exception):
30
+ def __init__(self, clause: ClauseInfo[T], *args):
31
+ self.clause = clause
32
+ super().__init__(*args)
33
+
34
+ def __str__(self):
35
+ agg_methods = self.__get_all_aggregate_method(self.clause)
36
+ return f"You cannot use aggregation method like '{agg_methods}' to return model objects. Try specifying 'flavour' attribute as 'dict'."
37
+
38
+ def __get_all_aggregate_method(self, clauses: list[ClauseInfo]) -> str:
39
+ """
40
+ Get the class name of those classes that inherit from 'AggregateFunctionBase' class in order to create a better error message.
41
+ """
42
+ from ormlambda.sql.clause_info import AggregateFunctionBase
43
+
44
+ res: set[str] = set()
45
+ if not isinstance(clauses, tp.Iterable):
46
+ return clauses.__class__.__name__
47
+ for clause in clauses:
48
+ if isinstance(clause, AggregateFunctionBase):
49
+ res.add(clause.__class__.__name__)
50
+ return ", ".join(res)
@@ -1,12 +1,16 @@
1
+ from __future__ import annotations
1
2
  from abc import abstractmethod, ABC
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from ormlambda.dialects import Dialect
2
7
 
3
8
 
4
9
  class IQuery(ABC):
5
10
  """Interface to queries that retrieve any element such as select, limit, offset, where, group by, etc..."""
6
11
 
7
- @property
8
12
  @abstractmethod
9
- def query(self) -> str: ...
13
+ def query(self, dialect: Dialect, **kwargs) -> str: ...
10
14
 
11
15
  def __repr__(self) -> str:
12
16
  return f"{IQuery.__name__}: {self.__class__.__name__}"
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+ from typing import Callable, Optional, Type, TYPE_CHECKING
3
+ from ormlambda import util
4
+ import importlib
5
+
6
+ if TYPE_CHECKING:
7
+ from .interface import Dialect
8
+
9
+
10
+ __all__ = ("mysql", "sqlite")
11
+
12
+
13
+ def _auto_fn(name: str) -> Optional[Callable[[], Type[Dialect]]]:
14
+ """default dialect importer.
15
+
16
+ plugs into the :class:`.PluginLoader`
17
+ as a first-hit system.
18
+
19
+ """
20
+ if "." in name:
21
+ dialect, driver = name.split(".")
22
+ else:
23
+ dialect = name
24
+ driver = "base"
25
+
26
+ try:
27
+ module = importlib.import_module(f"ormlambda.dialects.{dialect}")
28
+
29
+ except ImportError:
30
+ return None
31
+
32
+ if hasattr(module, driver):
33
+ module = getattr(module, driver)
34
+ return lambda: module.dialect
35
+ else:
36
+ return None
37
+
38
+
39
+ registry = util.PluginLoader("ormlambda.dialects", auto_fn=_auto_fn)
@@ -0,0 +1 @@
1
+ from .base import DefaultDialect
@@ -0,0 +1,39 @@
1
+ from ormlambda.dialects.interface import Dialect
2
+ from ormlambda.sql import compiler
3
+ from typing import Optional, Any
4
+ from types import ModuleType
5
+ from ormlambda import BaseRepository
6
+
7
+
8
+ class DefaultDialect(Dialect):
9
+ """Default implementation of Dialect"""
10
+
11
+ statement_compiler = compiler.SQLCompiler
12
+ ddl_compiler = compiler.DDLCompiler
13
+ type_compiler_cls = compiler.GenericTypeCompiler
14
+ repository_cls = BaseRepository
15
+ default_paramstyle = "named"
16
+
17
+ def __init__(
18
+ self,
19
+ dbapi: Optional[ModuleType] = None, # type: ignore
20
+ **kwargs: Any,
21
+ ):
22
+ self.dbapi = dbapi
23
+
24
+ if self.dbapi is not None:
25
+ self.paramstyle = self.dbapi.paramstyle
26
+ else:
27
+ self.paramstyle = self.default_paramstyle
28
+ self.positional = self.paramstyle in (
29
+ "qmark",
30
+ "format",
31
+ "numeric",
32
+ "numeric_dollar",
33
+ )
34
+
35
+ tt_callable = self.type_compiler_cls
36
+
37
+ self.type_compiler_instance = self.type_compiler = tt_callable(self)
38
+
39
+ super().__init__(**kwargs)
@@ -0,0 +1 @@
1
+ from .dialect import Dialect # noqa: F401
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations
2
+ import abc
3
+ from typing import ClassVar, Optional, Type, TYPE_CHECKING
4
+
5
+
6
+ if TYPE_CHECKING:
7
+ from ormlambda.caster.caster import Caster
8
+ from ormlambda.repository.interfaces.IRepositoryBase import DBAPIConnection
9
+ from ormlambda.sql.types import DDLCompiler, SQLCompiler, TypeCompiler
10
+ from ormlambda import BaseRepository
11
+
12
+
13
+ class Dialect(abc.ABC):
14
+ """
15
+ Abstract base class for all database dialects.
16
+ """
17
+
18
+ dbapi: Optional[DBAPIConnection]
19
+ """A reference to the DBAPI module object itself.
20
+
21
+ Ormlambda dialects import DBAPI modules using the classmethod
22
+ :meth:`.Dialect.import_dbapi`. The rationale is so that any dialect
23
+ module can be imported and used to generate SQL statements without the
24
+ need for the actual DBAPI driver to be installed. Only when an
25
+ :class:`.Engine` is constructed using :func:`.create_engine` does the
26
+ DBAPI get imported; at that point, the creation process will assign
27
+ the DBAPI module to this attribute.
28
+
29
+ Dialects should therefore implement :meth:`.Dialect.import_dbapi`
30
+ which will import the necessary module and return it, and then refer
31
+ to ``self.dbapi`` in dialect code in order to refer to the DBAPI module
32
+ contents.
33
+
34
+ .. versionchanged:: The :attr:`.Dialect.dbapi` attribute is exclusively
35
+ used as the per-:class:`.Dialect`-instance reference to the DBAPI
36
+ module. The previous not-fully-documented ``.Dialect.dbapi()``
37
+ classmethod is deprecated and replaced by :meth:`.Dialect.import_dbapi`.
38
+
39
+ """
40
+
41
+ name: ClassVar[str]
42
+ """The name of the dialect, e.g. 'sqlite', 'postgresql', etc."""
43
+ driver: ClassVar[str]
44
+ """The driver used by the dialect, e.g. 'sqlite3', 'psycopg2', etc."""
45
+
46
+ ddl_compiler: ClassVar[Type[DDLCompiler]]
47
+ """The DDL compiler class used by the dialect."""
48
+
49
+ statement_compiler: ClassVar[Type[SQLCompiler]]
50
+ """The statement compiler class used by the dialect."""
51
+
52
+ type_compiler_cls: ClassVar[Type[TypeCompiler]]
53
+ """The type compiler class used by the dialect."""
54
+
55
+ type_compiler_instance: ClassVar[TypeCompiler]
56
+ """The instance of the type compiler class used by the dialect."""
57
+
58
+ repository_cls: ClassVar[Type[BaseRepository]]
59
+ """The repository class used by the dialect."""
60
+
61
+ caster: ClassVar[Type[Caster]]
62
+
63
+ @classmethod
64
+ def get_dialect_cls(cls) -> Type[Dialect]:
65
+ return cls
66
+
67
+ @classmethod
68
+ @abc.abstractmethod
69
+ def import_dbapi(cls) -> DBAPIConnection:
70
+ """
71
+ Import the DB API module for the dialect.
72
+ This method should be implemented by subclasses to import the
73
+ appropriate DB API module for the dialect.
74
+ """
75
+ ...
76
+
77
+ def __repr__(self):
78
+ return f"{Dialect.__name__}: {type(self).__name__}"
@@ -0,0 +1,38 @@
1
+ from . import base
2
+ from . import mysqlconnector
3
+
4
+ from .types import ( # noqa: F401
5
+ NUMERIC,
6
+ DECIMAL,
7
+ DOUBLE,
8
+ REAL,
9
+ FLOAT,
10
+ INTEGER,
11
+ BIGINT,
12
+ MEDIUMINT,
13
+ TINYINT,
14
+ SMALLINT,
15
+ BIT,
16
+ TIME,
17
+ TIMESTAMP,
18
+ DATETIME,
19
+ YEAR,
20
+ TEXT,
21
+ TINYTEXT,
22
+ MEDIUMTEXT,
23
+ LONGTEXT,
24
+ VARCHAR,
25
+ CHAR,
26
+ NVARCHAR,
27
+ NCHAR,
28
+ TINYBLOB,
29
+ MEDIUMBLOB,
30
+ LONGBLOB,
31
+ )
32
+
33
+
34
+ from .repository import MySQLRepository # noqa: F401
35
+ from .caster import MySQLCaster # noqa: F401
36
+
37
+ # default dialect
38
+ base.dialect = dialect = mysqlconnector.dialect