ormlambda 2.8.0__tar.gz → 2.9.0__tar.gz

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 (81) hide show
  1. {ormlambda-2.8.0 → ormlambda-2.9.0}/PKG-INFO +3 -2
  2. {ormlambda-2.8.0 → ormlambda-2.9.0}/pyproject.toml +4 -2
  3. ormlambda-2.9.0/src/ormlambda/__init__.py +20 -0
  4. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/abstract_classes/abstract_model.py +16 -17
  5. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/abstract_classes/decomposition_query.py +23 -0
  6. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/interfaces/IStatements.py +37 -30
  7. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/insert.py +24 -12
  8. ormlambda-2.9.0/src/ormlambda/databases/my_sql/clauses/order.py +47 -0
  9. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/select.py +8 -4
  10. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/update.py +11 -17
  11. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/repository.py +56 -6
  12. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/statements.py +26 -18
  13. ormlambda-2.9.0/src/ormlambda/utils/column.py +105 -0
  14. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/dtypes.py +4 -12
  15. ormlambda-2.9.0/src/ormlambda/utils/fields.py +60 -0
  16. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/table_constructor.py +67 -95
  17. ormlambda-2.8.0/src/ormlambda/__init__.py +0 -11
  18. ormlambda-2.8.0/src/ormlambda/databases/my_sql/clauses/order.py +0 -33
  19. ormlambda-2.8.0/src/ormlambda/utils/column.py +0 -66
  20. {ormlambda-2.8.0 → ormlambda-2.9.0}/LICENSE +0 -0
  21. {ormlambda-2.8.0 → ormlambda-2.9.0}/README.md +0 -0
  22. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/__init__.py +0 -0
  23. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/abstract_classes/__init__.py +0 -0
  24. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/abstract_classes/non_query_base.py +0 -0
  25. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/abstract_classes/query_base.py +0 -0
  26. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/enums/__init__.py +0 -0
  27. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/enums/condition_types.py +0 -0
  28. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/enums/join_type.py +0 -0
  29. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/interfaces/IAggregate.py +0 -0
  30. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/interfaces/IDecompositionQuery.py +0 -0
  31. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/interfaces/INonQueryCommand.py +0 -0
  32. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/interfaces/IQueryCommand.py +0 -0
  33. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/interfaces/IRepositoryBase.py +0 -0
  34. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/common/interfaces/__init__.py +0 -0
  35. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/__init__.py +0 -0
  36. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/delete/IDelete.py +0 -0
  37. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/delete/__init__.py +0 -0
  38. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/delete/abstract_delete.py +0 -0
  39. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/insert/IInsert.py +0 -0
  40. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/insert/__init__.py +0 -0
  41. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/insert/abstract_insert.py +0 -0
  42. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/update/IUpdate.py +0 -0
  43. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/update/__init__.py +0 -0
  44. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/update/abstract_update.py +0 -0
  45. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/upsert/IUpsert.py +0 -0
  46. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/upsert/__init__.py +0 -0
  47. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/upsert/abstract_upsert.py +0 -0
  48. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/where/__init__.py +0 -0
  49. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/components/where/abstract_where.py +0 -0
  50. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/__init__.py +0 -0
  51. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/__init__.py +0 -0
  52. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/__init__.py +0 -0
  53. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/count.py +0 -0
  54. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/create_database.py +0 -0
  55. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/delete.py +0 -0
  56. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/drop_database.py +0 -0
  57. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/drop_table.py +0 -0
  58. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/group_by.py +0 -0
  59. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/joins.py +0 -0
  60. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/limit.py +0 -0
  61. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/offset.py +0 -0
  62. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/upsert.py +0 -0
  63. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/clauses/where_condition.py +0 -0
  64. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/functions/__init__.py +0 -0
  65. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/functions/concat.py +0 -0
  66. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/functions/max.py +0 -0
  67. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/functions/min.py +0 -0
  68. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/databases/my_sql/functions/sum.py +0 -0
  69. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/model_base.py +0 -0
  70. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/__init__.py +0 -0
  71. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/foreign_key.py +0 -0
  72. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/lambda_disassembler/__init__.py +0 -0
  73. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/lambda_disassembler/dis_types.py +0 -0
  74. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/lambda_disassembler/disassembler.py +0 -0
  75. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/lambda_disassembler/dtypes.py +0 -0
  76. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/lambda_disassembler/name_of.py +0 -0
  77. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/lambda_disassembler/nested_element.py +0 -0
  78. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/lambda_disassembler/tree_instruction.py +0 -0
  79. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/module_tree/__init__.py +0 -0
  80. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/module_tree/dfs_traversal.py +0 -0
  81. {ormlambda-2.8.0 → ormlambda-2.9.0}/src/ormlambda/utils/module_tree/dynamic_module.py +0 -0
@@ -1,14 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ormlambda
3
- Version: 2.8.0
3
+ Version: 2.9.0
4
4
  Summary: ORM designed to interact with the database (currently with MySQL) using lambda functions and nested functions
5
5
  Author: p-hzamora
6
6
  Author-email: p.hzamora@icloud.com
7
7
  Requires-Python: >=3.12,<4.0
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.12
10
- Requires-Dist: fluent-validation (>=3.1.0,<4.0.0)
10
+ Requires-Dist: fluent-validation (==4.3.1)
11
11
  Requires-Dist: mysql-connector-python (>=9.0.0,<10.0.0)
12
+ Requires-Dist: shapely (>=2.0.6,<3.0.0)
12
13
  Description-Content-Type: text/markdown
13
14
 
14
15
  ![PyPI version](https://img.shields.io/pypi/v/ormlambda.svg)
@@ -3,7 +3,7 @@ line-length = 320
3
3
 
4
4
  [tool.poetry]
5
5
  name = "ormlambda"
6
- version = "2.8.0"
6
+ version = "2.9.0"
7
7
  description = "ORM designed to interact with the database (currently with MySQL) using lambda functions and nested functions"
8
8
  authors = ["p-hzamora <p.hzamora@icloud.com>"]
9
9
  readme = "README.md"
@@ -11,12 +11,14 @@ readme = "README.md"
11
11
  [tool.poetry.dependencies]
12
12
  python = "^3.12"
13
13
  mysql-connector-python= "^9.0.0"
14
- fluent-validation = "^3.1.0"
14
+ fluent-validation = "4.3.1"
15
+ shapely = "^2.0.6"
15
16
 
16
17
  [tool.poetry.group.test.dependencies]
17
18
  pandas = "^2.2.2"
18
19
  ruff = "^0.4.5"
19
20
  python-decouple = "^3.8"
21
+ parameterized = "^0.9.0"
20
22
 
21
23
 
22
24
  [build-system]
@@ -0,0 +1,20 @@
1
+ # region enums
2
+ from .common.enums import (
3
+ JoinType as JoinType,
4
+ ConditionType as ConditionType,
5
+ )
6
+ from ormlambda.common.interfaces.IStatements import OrderType as OrderType
7
+ # endregion
8
+
9
+ from .common.abstract_classes import AbstractSQLStatements as AbstractSQLStatements
10
+ from .common.interfaces import IRepositoryBase as IRepositoryBase
11
+ from .utils import (
12
+ Table as Table,
13
+ Column as Column,
14
+ ForeignKey as ForeignKey,
15
+ )
16
+ from .utils.lambda_disassembler import (
17
+ Disassembler as Disassembler,
18
+ nameof as nameof,
19
+ )
20
+ from .model_base import BaseModel as BaseModel # COMMENT: to avoid relative import we need to import BaseModel after import Table,Column, ForeignKey, IRepositoryBase and Disassembler
@@ -10,7 +10,6 @@ from ormlambda.common.interfaces.IAggregate import IAggregate
10
10
 
11
11
  if TYPE_CHECKING:
12
12
  from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase
13
- from ormlambda.components.select import ISelect
14
13
  from ormlambda.common.abstract_classes.decomposition_query import ClauseInfo
15
14
 
16
15
 
@@ -46,11 +45,11 @@ class AbstractSQLStatements[T: Table, TRepo](IStatements_two_generic[T, TRepo]):
46
45
  @override
47
46
  def repository(self) -> IRepositoryBase[TRepo]: ...
48
47
 
49
- def _return_flavour[TValue](self, query, flavour: Type[TValue]) -> tuple[TValue]:
50
- return self._repository.read_sql(query, flavour=flavour)
48
+ def _return_flavour[TValue](self, query, flavour: Type[TValue], select) -> tuple[TValue]:
49
+ return self._repository.read_sql(query, flavour=flavour, model=self._model, select=select)
51
50
 
52
- def _return_model(self, select: ISelect, query: str):
53
- response_sql = self._repository.read_sql(query, flavour=dict) # store all columns of the SQL query
51
+ def _return_model(self, select, query: str):
52
+ response_sql = self._repository.read_sql(query, flavour=dict, model=self._model, select=select) # store all columns of the SQL query
54
53
 
55
54
  if isinstance(response_sql, Iterable):
56
55
  return ClusterQuery[T](select, response_sql).clean_response()
@@ -66,7 +65,16 @@ class ClusterQuery[T]:
66
65
  self._select: DecompositionQueryBase[T] = select
67
66
  self._response_sql: tuple[dict[str, Any]] = response_sql
68
67
 
69
- def loop_foo(self) -> dict[Type[Table], list[Table]]:
68
+ def clean_response(self) -> tuple[dict[Type[Table], tuple[Table]]]:
69
+ tbl_dicc: dict[Type[Table], list[Table]] = self.__loop_foo()
70
+
71
+ # it not depend of flavour attr
72
+ for key, val in tbl_dicc.items():
73
+ tbl_dicc[key] = tuple(val)
74
+
75
+ return tuple(tbl_dicc.values())
76
+
77
+ def __loop_foo(self) -> dict[Type[Table], list[Table]]:
70
78
  # We must ensure to get the valid attributes for each instance
71
79
  table_initialize = defaultdict(list)
72
80
 
@@ -75,7 +83,7 @@ class ClusterQuery[T]:
75
83
  valid_attr: dict[str, Any] = {}
76
84
  for clause in clauses:
77
85
  if not hasattr(table, clause.column):
78
- agg_methods = self.get_all_aggregate_method(clauses)
86
+ agg_methods = self.__get_all_aggregate_method(clauses)
79
87
  raise ValueError(f"You cannot use aggregation method like '{agg_methods}' to return model objects. Try specifying 'flavour' attribute as 'dict'.")
80
88
  valid_attr[clause.column] = dicc_cols[clause.alias]
81
89
 
@@ -83,7 +91,7 @@ class ClusterQuery[T]:
83
91
  table_initialize[table].append(table(**valid_attr))
84
92
  return table_initialize
85
93
 
86
- def get_all_aggregate_method(self, clauses: list[ClauseInfo]) -> str:
94
+ def __get_all_aggregate_method(self, clauses: list[ClauseInfo]) -> str:
87
95
  res: set[str] = set()
88
96
 
89
97
  for clause in clauses:
@@ -91,12 +99,3 @@ class ClusterQuery[T]:
91
99
  if isinstance(row, IAggregate):
92
100
  res.add(row.__class__.__name__)
93
101
  return ", ".join(res)
94
-
95
- def clean_response(self) -> tuple[dict[Type[Table], tuple[Table]]]:
96
- tbl_dicc: dict[Type[Table], list[Table]] = self.loop_foo()
97
-
98
- # it not depend of flavour attr
99
- for key, val in tbl_dicc.items():
100
- tbl_dicc[key] = tuple(val)
101
-
102
- return tuple(tbl_dicc.values())
@@ -44,6 +44,13 @@ class ClauseInfo[T: tp.Type[Table]]:
44
44
  def query(self) -> str:
45
45
  return self._query
46
46
 
47
+ @property
48
+ def dtype[TProp](self) -> tp.Optional[tp.Type[TProp]]:
49
+ try:
50
+ return self._table.get_column(self.column).dtype
51
+ except ValueError:
52
+ return None
53
+
47
54
  def _resolve_column(self, data: ClauseDataType) -> str:
48
55
  if isinstance(data, property):
49
56
  return self._table.__properties_mapped__[data]
@@ -73,6 +80,17 @@ class ClauseInfo[T: tp.Type[Table]]:
73
80
 
74
81
 
75
82
  class DecompositionQueryBase[T: tp.Type[Table]](IDecompositionQuery[T]):
83
+ @tp.overload
84
+ def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]]) -> None: ...
85
+ @tp.overload
86
+ def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]], *, alias: bool = ...) -> None: ...
87
+ @tp.overload
88
+ def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]], *, alias: bool = ..., alias_name: tp.Optional[str] = ...) -> None: ...
89
+ @tp.overload
90
+ def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]], *, alias: bool = ..., alias_name: tp.Optional[str] = ..., by: JoinType = ...) -> None: ...
91
+ @tp.overload
92
+ def __init__[*Ts](self, table: T, lambda_query: tp.Callable[[T], tuple[*Ts]], *, alias: bool = ..., alias_name: tp.Optional[str] = ..., by: JoinType = ..., replace_asterisk_char: bool = ...) -> None: ...
93
+
76
94
  def __init__[*Ts](
77
95
  self,
78
96
  table: T,
@@ -98,6 +116,11 @@ class DecompositionQueryBase[T: tp.Type[Table]](IDecompositionQuery[T]):
98
116
 
99
117
  self.__clauses_list_generetor(lambda_query)
100
118
 
119
+ def __getitem__(self, key: str) -> ClauseInfo:
120
+ for clause in self._all_clauses:
121
+ if clause.alias == key:
122
+ return clause
123
+
101
124
  def alias_children_resolver[Tclause: tp.Type[Table]](self, clause_info: ClauseInfo[Tclause]):
102
125
  DEFAULT_ALIAS: str = f"{clause_info._table.__table_name__}_{clause_info._column}"
103
126
 
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
  from typing import Any, Callable, Iterable, Optional, Literal, Type, Union, overload, TYPE_CHECKING, TypeVar
3
3
  from enum import Enum
4
4
  from abc import abstractmethod, ABC
5
+ import enum
5
6
 
6
7
  from .IRepositoryBase import IRepositoryBase
7
8
  from ormlambda.common.enums import JoinType
@@ -10,7 +11,15 @@ if TYPE_CHECKING:
10
11
  from ormlambda import Table
11
12
  from .IAggregate import IAggregate
12
13
 
13
- OrderType = Literal["ASC", "DESC"]
14
+
15
+ class OrderType(enum.Enum):
16
+ ASC = "ASC"
17
+ DESC = "DESC"
18
+
19
+
20
+ OrderTypeString = Literal["ASC", "DESC"]
21
+
22
+ OrderTypes = OrderTypeString | OrderType | Iterable[OrderType]
14
23
 
15
24
  # TODOH: This var is duplicated from 'src\ormlambda\databases\my_sql\clauses\create_database.py'
16
25
  TypeExists = Literal["fail", "replace", "append"]
@@ -109,7 +118,7 @@ class IStatements[T: Table](ABC):
109
118
  @overload
110
119
  def delete(self, instance: list[T]) -> None: ...
111
120
  @abstractmethod
112
- def delete(self, instance: Optional[T | list[T]] = None) -> None: ...
121
+ def delete(self, instance: Optional[T | list[T]] = ...) -> None: ...
113
122
 
114
123
  # endregion
115
124
  # region join
@@ -155,9 +164,9 @@ class IStatements[T: Table](ABC):
155
164
  @overload
156
165
  def order[TValue](self, _lambda_col: Callable[[T], TValue]) -> IStatements[T]: ...
157
166
  @overload
158
- def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderType) -> IStatements[T]: ...
167
+ def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderTypes) -> IStatements[T]: ...
159
168
  @abstractmethod
160
- def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderType) -> IStatements[T]: ...
169
+ def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderTypes) -> IStatements[T]: ...
161
170
 
162
171
  # endregion
163
172
  # region concat
@@ -196,62 +205,60 @@ class IStatements[T: Table](ABC):
196
205
  @overload
197
206
  def select(self) -> tuple[T, ...]: ...
198
207
  @overload
199
- def select[T1](self, selector: Callable[[T], T1], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...]]: ...
208
+ def select[T1](self, selector: Callable[[T], T1], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...]]: ...
200
209
  @overload
201
- def select[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...]]: ...
210
+ def select[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...]]: ...
202
211
  @overload
203
- def select[T1, T2](self, selector: Callable[[T], tuple[T1, T2]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...]]: ...
212
+ def select[T1, T2](self, selector: Callable[[T], tuple[T1, T2]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...]]: ...
204
213
  @overload
205
- def select[T1, T2, T3](self, selector: Callable[[T], tuple[T1, T2, T3]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...]]: ...
214
+ def select[T1, T2, T3](self, selector: Callable[[T], tuple[T1, T2, T3]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...]]: ...
206
215
  @overload
207
- def select[T1, T2, T3, T4](self, selector: Callable[[T], tuple[T1, T2, T3, T4]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...]]: ...
216
+ def select[T1, T2, T3, T4](self, selector: Callable[[T], tuple[T1, T2, T3, T4]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...]]: ...
208
217
  @overload
209
- def select[T1, T2, T3, T4, T5](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...]]: ...
218
+ def select[T1, T2, T3, T4, T5](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...]]: ...
210
219
  @overload
211
- def select[T1, T2, T3, T4, T5, T6](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...]]: ...
220
+ def select[T1, T2, T3, T4, T5, T6](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...]]: ...
212
221
  @overload
213
- def select[T1, T2, T3, T4, T5, T6, T7](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...]]: ...
222
+ def select[T1, T2, T3, T4, T5, T6, T7](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...]]: ...
214
223
  @overload
215
- def select[T1, T2, T3, T4, T5, T6, T7, T8](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...]]: ...
224
+ def select[T1, T2, T3, T4, T5, T6, T7, T8](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...]]: ...
216
225
  @overload
217
- def select[T1, T2, T3, T4, T5, T6, T7, T8, T9](
218
- self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9]], *, by: Optional[Enum] = JoinType.INNER_JOIN
219
- ) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...], tuple[T9, ...]]: ...
226
+ def select[T1, T2, T3, T4, T5, T6, T7, T8, T9](self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9]], *, by: Optional[Enum] = ...) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...], tuple[T9, ...]]: ...
220
227
  @overload
221
228
  def select[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](
222
- self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]], *, by: Optional[Enum] = JoinType.INNER_JOIN
229
+ self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]], *, by: Optional[Enum] = ...
223
230
  ) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...], tuple[T9, ...], tuple[T10, ...]]: ...
224
231
  @overload
225
- def select[Ts](self, selector: Optional[Callable[[T], Ts]] = None, *, flavour: Type[tuple], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[Ts, ...]: ...
232
+ def select[Ts](self, selector: Optional[Callable[[T], Ts]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ...) -> tuple[Ts, ...]: ...
226
233
  @overload
227
- def select[Ts](self, selector: Optional[Callable[[T], tuple[Ts]]] = None, *, flavour: Type[tuple], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[Ts, ...]: ...
234
+ def select[Ts](self, selector: Optional[Callable[[T], tuple[Ts]]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ...) -> tuple[Ts, ...]: ...
228
235
  @overload
229
- def select[*Ts](self, selector: Optional[Callable[[T], tuple[*Ts]]] = None, *, flavour: Type[tuple], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[*Ts]]: ...
236
+ def select[*Ts](self, selector: Optional[Callable[[T], tuple[*Ts]]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ...) -> tuple[tuple[*Ts]]: ...
230
237
  @overload
231
- def select[TFlavour](self, selector: Optional[Callable[[T], tuple]] = None, *, flavour: Type[TFlavour], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[TFlavour]: ...
238
+ def select[TFlavour](self, selector: Optional[Callable[[T], tuple]] = ..., *, flavour: Type[TFlavour], by: Optional[Enum] = ...) -> tuple[TFlavour]: ...
232
239
  @abstractmethod
233
- def select[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = lambda: None, *, flavour: Type[TFlavour] = None, by: JoinType = JoinType.INNER_JOIN): ...
240
+ def select[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = ..., *, flavour: Type[TFlavour] = ..., by: JoinType = ...): ...
234
241
 
235
242
  # endregion
236
243
  # region select_one
237
244
  @overload
238
245
  def select_one(self) -> T: ...
239
246
  @overload
240
- def select_one[TFlavour](self, *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[TFlavour]) -> TFlavour: ...
247
+ def select_one[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour]) -> TFlavour: ...
241
248
  @overload
242
- def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> T1: ...
249
+ def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = ...) -> T1: ...
243
250
  @overload
244
- def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[*Ts]: ...
251
+ def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = ...) -> tuple[*Ts]: ...
245
252
  @overload
246
- def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type) -> T1: ...
253
+ def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type) -> T1: ...
247
254
  @overload
248
- def select_one[T1, TFlavour](self, selector: Callable[[T], T1], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[TFlavour]) -> T1: ...
255
+ def select_one[T1, TFlavour](self, selector: Callable[[T], T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour]) -> T1: ...
249
256
  @overload
250
- def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[tuple]) -> tuple[*Ts]: ...
257
+ def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = ..., flavour: Type[tuple]) -> tuple[*Ts]: ...
251
258
  @overload
252
- def select_one[TFlavour](self, selector: Callable[[T], tuple], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[TFlavour]) -> TFlavour: ...
259
+ def select_one[TFlavour](self, selector: Callable[[T], tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour]) -> TFlavour: ...
253
260
  @abstractmethod
254
- def select_one[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = lambda: None, *, flavour: Type[TFlavour] = None, by: Optional[Enum] = JoinType.INNER_JOIN): ...
261
+ def select_one[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = lambda: None, *, flavour: Type[TFlavour] = ..., by: Optional[Enum] = ...): ...
255
262
 
256
263
  # endregion
257
264
  # region group_by
@@ -1,4 +1,4 @@
1
- from typing import Any, override, Iterable
1
+ from typing import override, Iterable
2
2
  from mysql.connector import MySQLConnection
3
3
 
4
4
  from ormlambda import Table
@@ -24,13 +24,24 @@ class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase[MySQLConnection]]
24
24
 
25
25
  @override
26
26
  def insert(self, instances: T | list[T]) -> None:
27
- new_dict_list: list[dict[str, Any]] = []
28
- self.__fill_dict_list(new_dict_list, instances)
29
- cols_tuple = new_dict_list[0].keys()
30
- join_cols = ", ".join(cols_tuple)
31
- unknown_rows = f'({", ".join(["%s"]*len(cols_tuple))})' # The number of "%s" must match the dict 'dicc_0' length
27
+ valid_cols: list[list[Column]] = []
28
+ self.__fill_dict_list(valid_cols, instances)
32
29
 
33
- self._values = [tuple(x.values()) for x in new_dict_list]
30
+ col_names: list[str] = []
31
+ wildcards: list[str] = []
32
+ col_values: list[list[str]] = []
33
+ for i, cols in enumerate(valid_cols):
34
+ col_values.append([])
35
+ for col in cols:
36
+ if i == 0:
37
+ col_names.append(col.column_name)
38
+ wildcards.append(col.placeholder)
39
+ col_values[-1].append(col.column_value_to_query)
40
+
41
+ join_cols = ", ".join(col_names)
42
+ unknown_rows = f'({", ".join(wildcards)})' # The number of "%s" must match the dict 'dicc_0' length
43
+
44
+ self._values = [tuple(x) for x in col_values]
34
45
  self._query = f"{self.CLAUSE} {self._model.__table_name__} {f'({join_cols})'} VALUES {unknown_rows}"
35
46
  return None
36
47
 
@@ -55,17 +66,18 @@ class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase[MySQLConnection]]
55
66
  return False
56
67
  return True
57
68
 
58
- def __fill_dict_list(self, list_dict: list[dict], values: T | list[T]):
69
+ def __fill_dict_list[TProp](self, list_dict: list[str, TProp], values: T | list[T]) -> list[Column]:
59
70
  if issubclass(values.__class__, Table):
60
- dicc: dict = {}
71
+ new_list = []
61
72
  for col in values.__dict__.values():
62
73
  if isinstance(col, Column) and self.__is_valid(col):
63
- dicc.update({col.column_name: col.column_value})
64
- list_dict.append(dicc)
65
- return list_dict
74
+ new_list.append(col)
75
+
76
+ list_dict.append(new_list)
66
77
 
67
78
  elif isinstance(values, Iterable):
68
79
  for x in values:
69
80
  self.__fill_dict_list(list_dict, x)
70
81
  else:
71
82
  raise Exception(f"Tipo de dato'{type(values)}' no esperado")
83
+ return None
@@ -0,0 +1,47 @@
1
+ from __future__ import annotations
2
+ from typing import override, Callable, TYPE_CHECKING, Any, Iterable
3
+
4
+ from ormlambda.common.abstract_classes.decomposition_query import ClauseInfo
5
+
6
+
7
+ if TYPE_CHECKING:
8
+ from ormlambda import Table
9
+
10
+ from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase
11
+ from ormlambda.common.interfaces.IStatements import OrderType
12
+
13
+
14
+ class OrderQuery[T: Table](DecompositionQueryBase[T]):
15
+ ORDER = "ORDER BY"
16
+
17
+ def __init__[*Ts](self, instance: T, lambda_query: Callable[[Any], tuple[*Ts]], order_type: Iterable[OrderType]) -> None:
18
+ super().__init__(instance, lambda_query)
19
+
20
+ if isinstance(order_type, str) or not isinstance(order_type, Iterable):
21
+ order_type = (order_type,)
22
+
23
+ self._order_type: list[OrderType] = [self.__cast_to_OrderType(x) for x in order_type]
24
+
25
+ def __cast_to_OrderType(self, _value: Any) -> Iterable[OrderType]:
26
+ if isinstance(_value, OrderType):
27
+ return _value
28
+
29
+ if isinstance(_value, str):
30
+ try:
31
+ return OrderType(_value)
32
+ except Exception:
33
+ pass
34
+ raise Exception(f"order_type param only can be 'ASC' or 'DESC' string or '{OrderType.__name__}' enum")
35
+
36
+ def alias_children_resolver[Tclause](self, clause_info: ClauseInfo[Tclause]):
37
+ return None
38
+
39
+ @override
40
+ @property
41
+ def query(self) -> str:
42
+ assert len(self.all_clauses) == len(self._order_type)
43
+
44
+ query: list[str] = []
45
+ for index, x in enumerate(self.all_clauses):
46
+ query.append(f"{x.query} {self._order_type[index].value}")
47
+ return f"{self.ORDER} {", ".join(query)}"
@@ -3,6 +3,7 @@ from typing import override, Type, Callable, TYPE_CHECKING
3
3
  from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase
4
4
  from ormlambda.common.enums.join_type import JoinType
5
5
  from ormlambda.common.interfaces.IAggregate import IAggregate
6
+ import shapely as shp
6
7
 
7
8
  if TYPE_CHECKING:
8
9
  from ormlambda import Table
@@ -32,17 +33,20 @@ class Select[T: Type[Table]](DecompositionQueryBase[T]):
32
33
  # def alias_children_resolver[Tclause: Type[Table]](self, clause_info: ClauseInfo[Tclause]):
33
34
  # return f"{clause.table.__table_name__}_{name}"
34
35
 
36
+ # TODOL: see who to deal when we will have to add more mysql methods
35
37
  @override
36
38
  @property
37
39
  def query(self) -> str:
38
- cols:list[str] = []
40
+ cols: list[str] = []
39
41
  for x in self.all_clauses:
40
- cols.append(x.query)
42
+ if x.dtype is shp.Point:
43
+ cols.append(x.concat_with_alias(f"ST_AsText({self._table.__table_name__}.{x.column})"))
44
+ else:
45
+ cols.append(x.query)
41
46
 
42
- if isinstance(x._row_column,IAggregate) and x._row_column.has_foreign_keys:
47
+ if isinstance(x._row_column, IAggregate) and x._row_column.has_foreign_keys:
43
48
  self._fk_relationship.update(x._row_column.fk_relationship)
44
49
 
45
-
46
50
  col: str = ", ".join(cols)
47
51
  query: str = f"{self.CLAUSE} {col} FROM {self._table.__table_name__}"
48
52
  alias = ""
@@ -27,26 +27,20 @@ class UpdateQuery[T: Type[Table]](UpdateQueryBase[T, IRepositoryBase[MySQLConnec
27
27
  if not isinstance(dicc, dict):
28
28
  raise TypeError
29
29
 
30
- name_cols: list[str] = []
30
+ name_cols: list[Column] = []
31
31
 
32
32
  for col, value in dicc.items():
33
- if isinstance(col, str):
34
- string_col = col
35
- else:
36
- string_col = self._model.__properties_mapped__.get(col, None)
37
- if not string_col:
38
- raise KeyError(f"Class '{self._model.__name__}' has not {col} mapped.")
39
- if self.__is_valid__(string_col, value):
40
- name_cols.append(string_col)
41
- self._values.append(value)
42
-
43
- set_query: str = ",".join(["=".join([col, "%s"]) for col in name_cols])
33
+ col: Column = self._model.get_column(col, value)
34
+
35
+ if self.__is_valid__(col):
36
+ name_cols.append(col)
37
+ self._values.append(col.column_value_to_query)
38
+
39
+ set_query: str = ",".join(["=".join([col.column_name, col.placeholder]) for col in name_cols])
44
40
 
45
41
  self._query = f"{self.CLAUSE} {self._model.__table_name__} SET {set_query}"
42
+ self._values = tuple(self._values)
46
43
  return None
47
44
 
48
- def __is_valid__(self, col: str, value: Any) -> bool:
49
- instance_table: Table = self._model(**{col: value})
50
-
51
- column: Column = getattr(instance_table, f"_{col}")
52
- return not column.is_auto_generated
45
+ def __is_valid__(self, col: Column) -> bool:
46
+ return not col.is_auto_generated
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
  from pathlib import Path
3
- from typing import Any, Optional, Type, override, Callable
3
+ from typing import Any, Optional, Type, override, Callable, TYPE_CHECKING
4
4
  import functools
5
+ import shapely as shp
5
6
 
6
7
  # from mysql.connector.pooling import MySQLConnectionPool
7
8
  from mysql.connector import MySQLConnection, Error # noqa: F401
@@ -16,12 +17,20 @@ from .clauses import DropDatabase
16
17
  from .clauses import DropTable
17
18
 
18
19
 
20
+ if TYPE_CHECKING:
21
+ from src.ormlambda.common.abstract_classes.decomposition_query import ClauseInfo
22
+ from ormlambda import Table
23
+ from src.ormlambda.databases.my_sql.clauses.select import Select
24
+
25
+
19
26
  class Response[TFlavour, *Ts]:
20
- def __init__(self, response_values: list[tuple[*Ts]], columns: tuple[str], flavour: Type[TFlavour], **kwargs) -> None:
27
+ def __init__(self, response_values: list[tuple[*Ts]], columns: tuple[str], flavour: Type[TFlavour], model: Optional[Table] = None, select: Optional[Select] = None, **kwargs) -> None:
21
28
  self._response_values: list[tuple[*Ts]] = response_values
22
29
  self._columns: tuple[str] = columns
23
30
  self._flavour: Type[TFlavour] = flavour
24
31
  self._kwargs: dict[str, Any] = kwargs
32
+ self._model: Table = model
33
+ self._select: Select = select
25
34
 
26
35
  self._response_values_index: int = len(self._response_values)
27
36
  # self.select_values()
@@ -42,8 +51,10 @@ class Response[TFlavour, *Ts]:
42
51
  def response(self) -> tuple[dict[str, tuple[*Ts]]] | tuple[tuple[*Ts]] | tuple[TFlavour]:
43
52
  if not self.is_there_response:
44
53
  return tuple([])
45
-
46
- return tuple(self._cast_to_flavour(self._response_values))
54
+ clean_response = self._response_values
55
+ if self._select is not None:
56
+ clean_response = self._parser_response()
57
+ return tuple(self._cast_to_flavour(clean_response))
47
58
 
48
59
  def _cast_to_flavour(self, data: list[tuple[*Ts]]) -> list[dict[str, tuple[*Ts]]] | list[tuple[*Ts]] | list[TFlavour]:
49
60
  def _dict() -> list[dict[str, tuple[*Ts]]]:
@@ -73,6 +84,38 @@ class Response[TFlavour, *Ts]:
73
84
 
74
85
  return selector.get(self._flavour, _default)()
75
86
 
87
+ def _parser_response(self) -> TFlavour:
88
+ new_response: list[list] = []
89
+ for row in self._response_values:
90
+ new_row: list = []
91
+ for i, data in enumerate(row):
92
+ alias = self._columns[i]
93
+ clause_info = self._select[alias]
94
+ if not self._is_parser_required(clause_info):
95
+ new_row = row
96
+ break
97
+ else:
98
+ parser_data = self.parser_data(clause_info, data)
99
+ new_row.append(parser_data)
100
+ if not isinstance(new_row, tuple):
101
+ new_row = tuple(new_row)
102
+
103
+ new_response.append(new_row)
104
+ return new_response
105
+
106
+ @staticmethod
107
+ def _is_parser_required[T: Table](clause_info: ClauseInfo[T]) -> bool:
108
+ if clause_info is None:
109
+ return False
110
+
111
+ return clause_info.dtype is shp.Point
112
+
113
+ @staticmethod
114
+ def parser_data[T: Table, TProp](clause_info: ClauseInfo[T], data: TProp):
115
+ if clause_info.dtype is shp.Point:
116
+ return shp.from_wkt(data)
117
+ return data
118
+
76
119
 
77
120
  class MySQLRepository(IRepositoryBase[MySQLConnection]):
78
121
  def get_connection(func: Callable[..., Any]):
@@ -107,11 +150,19 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
107
150
  - flavour: Type[TFlavour]: Useful to return tuple of any Iterable type as dict,set,list...
108
151
  """
109
152
 
153
+ def get_and_drop_key(key: str) -> Optional[Any]:
154
+ if key in kwargs:
155
+ return kwargs.pop(key)
156
+ return None
157
+
158
+ model: Table = get_and_drop_key("model")
159
+ select: Select = get_and_drop_key("select")
160
+
110
161
  with cnx.cursor(buffered=True) as cursor:
111
162
  cursor.execute(query)
112
163
  values: list[tuple] = cursor.fetchall()
113
164
  columns: tuple[str] = cursor.column_names
114
- return Response[TFlavour](response_values=values, columns=columns, flavour=flavour, **kwargs).response
165
+ return Response[TFlavour](model=model, response_values=values, columns=columns, flavour=flavour, select=select, **kwargs).response
115
166
 
116
167
  # FIXME [ ]: this method does not comply with the implemented interface
117
168
  @get_connection
@@ -192,7 +243,6 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
192
243
  def create_database(self, name: str, if_exists: TypeExists = "fail") -> None:
193
244
  return CreateDatabase(self).execute(name, if_exists)
194
245
 
195
-
196
246
  @property
197
247
  def database(self) -> Optional[str]:
198
248
  return self._data_config.get("database", None)