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
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__}"
@@ -1,5 +1,4 @@
1
1
  from .my_sql import (
2
2
  MySQLCaster as MySQLCaster,
3
3
  MySQLRepository as MySQLRepository,
4
- MySQLStatements as MySQLStatements,
5
4
  )
@@ -1,4 +1,3 @@
1
1
  from mysql.connector import MySQLConnection # noqa: F401
2
2
  from .repository import MySQLRepository # noqa: F401
3
- from .statements import MySQLStatements # noqa: F401
4
3
  from .caster import MySQLCaster # noqa: F401
@@ -1,18 +1,29 @@
1
1
  from __future__ import annotations
2
-
3
- from typing import Optional, get_args
4
- from ormlambda.caster import BaseCaster
5
- from ormlambda.caster import ICaster
6
-
7
-
8
- from .types import StringCaster, IntegerCaster, FloatCaster, PointCaster, NoneTypeCaster, DatetimeCaster, BytesCaster, IterableCaster
2
+ from ormlambda.caster.caster import Caster
3
+
4
+
5
+ from .types import (
6
+ StringCaster,
7
+ IntegerCaster,
8
+ FloatCaster,
9
+ PointCaster,
10
+ NoneTypeCaster,
11
+ DatetimeCaster,
12
+ BytesCaster,
13
+ IterableCaster,
14
+ BooleanCaster,
15
+ DecimalCaster,
16
+ )
9
17
 
10
18
  from shapely import Point
11
19
  from types import NoneType
12
- from datetime import datetime
20
+ from datetime import datetime, date
21
+ from decimal import Decimal
22
+
13
23
 
24
+ class MySQLCaster(Caster):
25
+ PLACEHOLDER = "%s"
14
26
 
15
- class MySQLCaster(ICaster):
16
27
  @classmethod
17
28
  def CASTER_SELECTOR(cls):
18
29
  return {
@@ -22,18 +33,11 @@ class MySQLCaster(ICaster):
22
33
  Point: PointCaster,
23
34
  NoneType: NoneTypeCaster,
24
35
  datetime: DatetimeCaster,
36
+ date: DatetimeCaster,
25
37
  bytes: BytesCaster,
26
38
  bytearray: BytesCaster,
27
39
  tuple: IterableCaster,
28
40
  list: IterableCaster,
41
+ bool: BooleanCaster,
42
+ Decimal: DecimalCaster,
29
43
  }
30
-
31
- @classmethod
32
- def cast[TProp, TType](cls, value: TProp, type_value: Optional[TType] = None) -> BaseCaster[TProp, TType]:
33
- if len(args := get_args(type_value)) > 1:
34
- args = [x for x in args if x != NoneType]
35
-
36
- type_value = args[0]
37
-
38
- column_type = type_value if type_value else type(value)
39
- return cls.CASTER_SELECTOR()[column_type](value, column_type)
@@ -6,3 +6,6 @@ from .none import NoneTypeCaster as NoneTypeCaster
6
6
  from .datetime import DatetimeCaster as DatetimeCaster
7
7
  from .bytes import BytesCaster as BytesCaster
8
8
  from .iterable import IterableCaster as IterableCaster
9
+ from .boolean import BooleanCaster as BooleanCaster
10
+ from .date import DateCaster as DateCaster
11
+ from .decimal import DecimalCaster as DecimalCaster
@@ -0,0 +1,35 @@
1
+ from typing import Optional
2
+ from ormlambda.caster import BaseCaster, Caster
3
+
4
+
5
+ class BooleanCaster[TType](BaseCaster[bool, TType]):
6
+ """
7
+ MySQL uses 0/1 for booleans stored in TINYINT
8
+ """
9
+
10
+ def __init__(self, value: bool, type_value: TType):
11
+ super().__init__(value, type_value)
12
+
13
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
14
+ return Caster.PLACEHOLDER if value is None else value
15
+
16
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
17
+ return Caster.PLACEHOLDER if value is None else value
18
+
19
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
20
+ return Caster.PLACEHOLDER if value is None else value
21
+
22
+ @property
23
+ @BaseCaster.return_value_if_exists
24
+ def to_database(self) -> Optional[int]:
25
+ return 1 if self.value else 0
26
+
27
+ @property
28
+ @BaseCaster.return_value_if_exists
29
+ def from_database(self) -> Optional[bool]:
30
+ return bool(self.value)
31
+
32
+ @property
33
+ @BaseCaster.return_value_if_exists
34
+ def string_data(self) -> Optional[str]:
35
+ return str(bool(self.value))
@@ -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 BytesCaster[TType](BaseCaster[bytes, TType]):
6
6
  def __init__(self, value: bytes, 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
@@ -0,0 +1,34 @@
1
+ from typing import Optional
2
+ from ormlambda.caster import BaseCaster, Caster
3
+ from datetime import datetime
4
+ from .string import StringCaster
5
+
6
+
7
+ class DateCaster[TType](BaseCaster[datetime, TType]):
8
+ def __init__(self, value: datetime, type_value: TType):
9
+ super().__init__(value, type_value)
10
+
11
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
12
+ return Caster.PLACEHOLDER if value is None else value
13
+
14
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
15
+ return Caster.PLACEHOLDER if value is None else value
16
+
17
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
18
+ return Caster.PLACEHOLDER if value is None else value
19
+
20
+ @property
21
+ @BaseCaster.return_value_if_exists
22
+ def to_database(self) -> Optional[datetime]:
23
+ return self.value
24
+
25
+ @property
26
+ @BaseCaster.return_value_if_exists
27
+ def from_database(self) -> Optional[datetime]:
28
+ return self.value
29
+
30
+ @property
31
+ @BaseCaster.return_value_if_exists
32
+ def string_data(self) -> Optional[str]:
33
+ datetime_string = self.value.strftime(r"%Y-%m-%d")
34
+ return StringCaster(datetime_string, str).string_data
@@ -1,5 +1,5 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
  from datetime import datetime
4
4
  from .string import StringCaster
5
5
 
@@ -8,14 +8,14 @@ class DatetimeCaster[TType](BaseCaster[datetime, TType]):
8
8
  def __init__(self, value: datetime, type_value: TType):
9
9
  super().__init__(value, type_value)
10
10
 
11
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
12
- return value
11
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
12
+ return Caster.PLACEHOLDER if value is None else value
13
13
 
14
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
15
- return value
14
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
15
+ return Caster.PLACEHOLDER if value is None else value
16
16
 
17
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
18
- return value
17
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
18
+ return Caster.PLACEHOLDER if value is None else value
19
19
 
20
20
  @property
21
21
  @BaseCaster.return_value_if_exists
@@ -0,0 +1,32 @@
1
+ from typing import Optional
2
+ from ormlambda.caster import BaseCaster, Caster
3
+ from decimal import Decimal
4
+
5
+
6
+ class DecimalCaster[TType](BaseCaster[Decimal, TType]):
7
+ def __init__(self, value: Decimal, type_value: TType):
8
+ super().__init__(value, type_value)
9
+
10
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
11
+ return Caster.PLACEHOLDER if value is None else value
12
+
13
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
14
+ return Caster.PLACEHOLDER if value is None else value
15
+
16
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
17
+ return Caster.PLACEHOLDER if value is None else value
18
+
19
+ @property
20
+ @BaseCaster.return_value_if_exists
21
+ def to_database(self) -> Optional[Decimal]:
22
+ return Decimal(self.value)
23
+
24
+ @property
25
+ @BaseCaster.return_value_if_exists
26
+ def from_database(self) -> Optional[Decimal]:
27
+ return Decimal(self.value)
28
+
29
+ @property
30
+ @BaseCaster.return_value_if_exists
31
+ def string_data(self) -> Optional[str]:
32
+ return str(self.value)
@@ -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 FloatCaster[TType](BaseCaster[float, TType]):
6
6
  def __init__(self, value: float, 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,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 IntegerCaster[TType](BaseCaster[int, TType]):
6
6
  def __init__(self, value: int, 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,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 IterableCaster[TType](BaseCaster[bytes, TType]):
6
6
  def __init__(self, value: bytes, 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,19 +1,20 @@
1
1
  from types import NoneType
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from typing import Optional
3
+ from ormlambda.caster import BaseCaster, Caster
3
4
 
4
5
 
5
6
  class NoneTypeCaster[TType](BaseCaster[NoneType, TType]):
6
7
  def __init__(self, value: NoneType, type_value: TType):
7
8
  super().__init__(value, type_value)
8
9
 
9
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
10
- return value
10
+ def wildcard_to_select(self, value: Optional[str] = None) -> str:
11
+ return Caster.PLACEHOLDER if value is None else value
11
12
 
12
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
13
- return value
13
+ def wildcard_to_where(self, value: Optional[str] = None) -> str:
14
+ return Caster.PLACEHOLDER if value is None else value
14
15
 
15
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
16
- return value
16
+ def wildcard_to_insert(self, value: Optional[str] = None) -> str:
17
+ return Caster.PLACEHOLDER if value is None else value
17
18
 
18
19
  # TODOL: cheched if it's right
19
20
  @property
@@ -1,5 +1,5 @@
1
1
  from typing import Optional
2
- from ormlambda.caster import BaseCaster, PLACEHOLDER
2
+ from ormlambda.caster import BaseCaster, Caster
3
3
  from shapely import Point
4
4
  import shapely.wkt as wkt
5
5
  from shapely import wkb
@@ -9,13 +9,13 @@ class PointCaster[TType](BaseCaster[Point, TType]):
9
9
  def __init__(self, value: bytes | str, type_value: TType):
10
10
  super().__init__(value, type_value)
11
11
 
12
- def wildcard_to_select(self, value: str = PLACEHOLDER) -> str:
12
+ def wildcard_to_select(self, value: str = Caster.PLACEHOLDER) -> str:
13
13
  return f"ST_AsText({value})"
14
14
 
15
- def wildcard_to_where(self, value: str = PLACEHOLDER) -> str:
15
+ def wildcard_to_where(self, value: str = Caster.PLACEHOLDER) -> str:
16
16
  return f"ST_AsText({value})"
17
17
 
18
- def wildcard_to_insert(self, value: str = PLACEHOLDER) -> str:
18
+ def wildcard_to_insert(self, value: str = Caster.PLACEHOLDER) -> str:
19
19
  return f"ST_GeomFromText({value})"
20
20
 
21
21
  @property