ormlambda 0.1.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.
- ormlambda/__init__.py +4 -0
- ormlambda/common/__init__.py +2 -0
- ormlambda/common/abstract_classes/__init__.py +3 -0
- ormlambda/common/abstract_classes/abstract_model.py +302 -0
- ormlambda/common/abstract_classes/non_query_base.py +33 -0
- ormlambda/common/abstract_classes/query_base.py +10 -0
- ormlambda/common/enums/__init__.py +2 -0
- ormlambda/common/enums/condition_types.py +16 -0
- ormlambda/common/enums/join_type.py +10 -0
- ormlambda/common/interfaces/INonQueryCommand.py +9 -0
- ormlambda/common/interfaces/IQueryCommand.py +11 -0
- ormlambda/common/interfaces/IRepositoryBase.py +67 -0
- ormlambda/common/interfaces/IStatements.py +227 -0
- ormlambda/common/interfaces/__init__.py +4 -0
- ormlambda/components/__init__.py +0 -0
- ormlambda/components/delete/IDelete.py +6 -0
- ormlambda/components/delete/__init__.py +2 -0
- ormlambda/components/delete/abstract_delete.py +14 -0
- ormlambda/components/insert/IInsert.py +6 -0
- ormlambda/components/insert/__init__.py +2 -0
- ormlambda/components/insert/abstract_insert.py +21 -0
- ormlambda/components/select/ISelect.py +14 -0
- ormlambda/components/select/__init__.py +2 -0
- ormlambda/components/select/table_column.py +39 -0
- ormlambda/components/update/IUpdate.py +7 -0
- ormlambda/components/update/__init__.py +2 -0
- ormlambda/components/update/abstract_update.py +25 -0
- ormlambda/components/upsert/IUpsert.py +6 -0
- ormlambda/components/upsert/__init__.py +2 -0
- ormlambda/components/upsert/abstract_upsert.py +21 -0
- ormlambda/components/where/__init__.py +1 -0
- ormlambda/components/where/abstract_where.py +11 -0
- ormlambda/databases/__init__.py +0 -0
- ormlambda/databases/my_sql/__init__.py +2 -0
- ormlambda/databases/my_sql/clauses/__init__.py +13 -0
- ormlambda/databases/my_sql/clauses/create_database.py +29 -0
- ormlambda/databases/my_sql/clauses/delete.py +54 -0
- ormlambda/databases/my_sql/clauses/drop_database.py +19 -0
- ormlambda/databases/my_sql/clauses/drop_table.py +23 -0
- ormlambda/databases/my_sql/clauses/insert.py +70 -0
- ormlambda/databases/my_sql/clauses/joins.py +103 -0
- ormlambda/databases/my_sql/clauses/limit.py +17 -0
- ormlambda/databases/my_sql/clauses/offset.py +17 -0
- ormlambda/databases/my_sql/clauses/order.py +29 -0
- ormlambda/databases/my_sql/clauses/select.py +172 -0
- ormlambda/databases/my_sql/clauses/update.py +52 -0
- ormlambda/databases/my_sql/clauses/upsert.py +68 -0
- ormlambda/databases/my_sql/clauses/where_condition.py +219 -0
- ormlambda/databases/my_sql/repository.py +192 -0
- ormlambda/databases/my_sql/statements.py +86 -0
- ormlambda/model_base.py +36 -0
- ormlambda/utils/__init__.py +3 -0
- ormlambda/utils/column.py +65 -0
- ormlambda/utils/dtypes.py +104 -0
- ormlambda/utils/foreign_key.py +36 -0
- ormlambda/utils/lambda_disassembler/__init__.py +4 -0
- ormlambda/utils/lambda_disassembler/dis_types.py +136 -0
- ormlambda/utils/lambda_disassembler/disassembler.py +69 -0
- ormlambda/utils/lambda_disassembler/dtypes.py +103 -0
- ormlambda/utils/lambda_disassembler/name_of.py +41 -0
- ormlambda/utils/lambda_disassembler/nested_element.py +44 -0
- ormlambda/utils/lambda_disassembler/tree_instruction.py +145 -0
- ormlambda/utils/module_tree/__init__.py +0 -0
- ormlambda/utils/module_tree/dfs_traversal.py +60 -0
- ormlambda/utils/module_tree/dynamic_module.py +237 -0
- ormlambda/utils/table_constructor.py +308 -0
- ormlambda-0.1.0.dist-info/LICENSE +21 -0
- ormlambda-0.1.0.dist-info/METADATA +268 -0
- ormlambda-0.1.0.dist-info/RECORD +70 -0
- ormlambda-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,227 @@
|
|
1
|
+
from typing import Any, Callable, Iterable, Optional, Literal, Type, overload
|
2
|
+
from enum import Enum
|
3
|
+
from abc import abstractmethod, ABC
|
4
|
+
|
5
|
+
from .IRepositoryBase import IRepositoryBase
|
6
|
+
from ..enums import JoinType
|
7
|
+
from ...utils import Table
|
8
|
+
|
9
|
+
OrderType = Literal["ASC", "DESC"]
|
10
|
+
|
11
|
+
|
12
|
+
class IStatements[T: Table](ABC):
|
13
|
+
@abstractmethod
|
14
|
+
def create_table(self) -> None: ...
|
15
|
+
|
16
|
+
@abstractmethod
|
17
|
+
def table_exists(self) -> bool: ...
|
18
|
+
|
19
|
+
# region insert
|
20
|
+
@overload
|
21
|
+
def insert(self, values: T) -> None:
|
22
|
+
"""
|
23
|
+
PARAMS
|
24
|
+
------
|
25
|
+
- values: Recieves a single object that must match the model's type
|
26
|
+
"""
|
27
|
+
...
|
28
|
+
|
29
|
+
@overload
|
30
|
+
def insert(self, values: list[T]) -> None:
|
31
|
+
"""
|
32
|
+
PARAMS
|
33
|
+
------
|
34
|
+
- values: Recieves a list of the same objects as the model
|
35
|
+
"""
|
36
|
+
...
|
37
|
+
|
38
|
+
@abstractmethod
|
39
|
+
def insert(self, values: T | list[T]) -> None: ...
|
40
|
+
|
41
|
+
# region upsert
|
42
|
+
@overload
|
43
|
+
def upsert(self, values: T) -> None:
|
44
|
+
"""
|
45
|
+
PARAMS
|
46
|
+
------
|
47
|
+
- values: Recieves a single object that must match the model's type
|
48
|
+
"""
|
49
|
+
...
|
50
|
+
|
51
|
+
@overload
|
52
|
+
def upsert(self, values: list[T]) -> None:
|
53
|
+
"""
|
54
|
+
PARAMS
|
55
|
+
------
|
56
|
+
- values: Recieves a list of the same objects as the model
|
57
|
+
"""
|
58
|
+
...
|
59
|
+
|
60
|
+
@abstractmethod
|
61
|
+
def upsert(self, values: list[T]) -> None:
|
62
|
+
"""
|
63
|
+
Try to insert new values in the table, if they exist, update them
|
64
|
+
"""
|
65
|
+
...
|
66
|
+
|
67
|
+
@abstractmethod
|
68
|
+
def update(self, dicc: dict[str | property, Any]) -> None: ...
|
69
|
+
|
70
|
+
# endregion
|
71
|
+
|
72
|
+
# region limit
|
73
|
+
@abstractmethod
|
74
|
+
def limit(self, number: int) -> "IStatements[T]": ...
|
75
|
+
|
76
|
+
# endregion
|
77
|
+
|
78
|
+
# region offset
|
79
|
+
@abstractmethod
|
80
|
+
def offset(self, number: int) -> "IStatements[T]": ...
|
81
|
+
|
82
|
+
# endregion
|
83
|
+
|
84
|
+
# region delete
|
85
|
+
@overload
|
86
|
+
def delete(self) -> None: ...
|
87
|
+
|
88
|
+
@overload
|
89
|
+
def delete(self, instance: T) -> None: ...
|
90
|
+
|
91
|
+
@overload
|
92
|
+
def delete(self, instance: list[T]) -> None: ...
|
93
|
+
@abstractmethod
|
94
|
+
def delete(self, instance: Optional[T | list[T]] = None) -> None: ...
|
95
|
+
|
96
|
+
# endregion
|
97
|
+
|
98
|
+
# region join
|
99
|
+
@abstractmethod
|
100
|
+
def join(self, table_left: Table, table_right: Table, *, by: str) -> "IStatements[T]": ...
|
101
|
+
|
102
|
+
# endregion
|
103
|
+
|
104
|
+
# region where
|
105
|
+
@overload
|
106
|
+
def where(self, lambda_: Callable[[T], bool]) -> "IStatements[T]":
|
107
|
+
"""
|
108
|
+
This method creates where clause by passing the lambda's condition
|
109
|
+
|
110
|
+
EXAMPLE
|
111
|
+
-
|
112
|
+
mb = BaseModel()
|
113
|
+
mb.where(lambda a: 10 <= a.city_id <= 100)
|
114
|
+
"""
|
115
|
+
...
|
116
|
+
|
117
|
+
@overload
|
118
|
+
def where(self, lambda_: Callable[[T], Iterable]) -> "IStatements[T]":
|
119
|
+
"""
|
120
|
+
This method creates where clause by passing the Iterable in lambda function
|
121
|
+
EXAMPLE
|
122
|
+
-
|
123
|
+
mb = BaseModel()
|
124
|
+
mb.where(lambda a: (a.city, ConditionType.REGEXP, r"^B"))
|
125
|
+
"""
|
126
|
+
...
|
127
|
+
|
128
|
+
@overload
|
129
|
+
def where(self, lambda_: Callable[[T], bool], **kwargs) -> "IStatements[T]":
|
130
|
+
"""
|
131
|
+
PARAM
|
132
|
+
-
|
133
|
+
|
134
|
+
-kwargs: Use this when you need to replace variables inside a lambda method. When working with lambda methods, all variables will be replaced by their own variable names. To avoid this, we need to pass key-value parameters to specify which variables we want to replace with their values.
|
135
|
+
|
136
|
+
EXAMPLE
|
137
|
+
-
|
138
|
+
mb = BaseModel()
|
139
|
+
|
140
|
+
external_data = "
|
141
|
+
mb.where(lambda a: a.city_id > external_data)
|
142
|
+
"""
|
143
|
+
...
|
144
|
+
|
145
|
+
@abstractmethod
|
146
|
+
def where(self, lambda_: Callable[[T], bool] = lambda: None, **kwargs) -> "IStatements[T]": ...
|
147
|
+
|
148
|
+
# endregion
|
149
|
+
|
150
|
+
# region order
|
151
|
+
@overload
|
152
|
+
def order[TValue](self, _lambda_col: Callable[[T], TValue]) -> "IStatements[T]": ...
|
153
|
+
@overload
|
154
|
+
def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderType) -> "IStatements[T]": ...
|
155
|
+
@abstractmethod
|
156
|
+
def order[TValue](self, _lambda_col: Callable[[T], TValue], order_type: OrderType) -> "IStatements[T]": ...
|
157
|
+
|
158
|
+
# endregion
|
159
|
+
|
160
|
+
# region select
|
161
|
+
@overload
|
162
|
+
def select(self) -> tuple[T, ...]: ...
|
163
|
+
@overload
|
164
|
+
def select[T1](self, selector: Callable[[T], T1], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...]]: ...
|
165
|
+
@overload
|
166
|
+
def select[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...]]: ...
|
167
|
+
@overload
|
168
|
+
def select[T1, T2](self, selector: Callable[[T], tuple[T1, T2]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[T1, ...], tuple[T2, ...]]: ...
|
169
|
+
@overload
|
170
|
+
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, ...]]: ...
|
171
|
+
@overload
|
172
|
+
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, ...]]: ...
|
173
|
+
@overload
|
174
|
+
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, ...]]: ...
|
175
|
+
@overload
|
176
|
+
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, ...]]: ...
|
177
|
+
@overload
|
178
|
+
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, ...]]: ...
|
179
|
+
@overload
|
180
|
+
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, ...]]: ...
|
181
|
+
@overload
|
182
|
+
def select[T1, T2, T3, T4, T5, T6, T7, T8, T9](
|
183
|
+
self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9]], *, by: Optional[Enum] = JoinType.INNER_JOIN
|
184
|
+
) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...], tuple[T9, ...]]: ...
|
185
|
+
@overload
|
186
|
+
def select[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](
|
187
|
+
self, selector: Callable[[T], tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]], *, by: Optional[Enum] = JoinType.INNER_JOIN
|
188
|
+
) -> tuple[tuple[T1, ...], tuple[T2, ...], tuple[T3, ...], tuple[T4, ...], tuple[T5, ...], tuple[T6, ...], tuple[T7, ...], tuple[T8, ...], tuple[T9, ...], tuple[T10, ...]]: ...
|
189
|
+
@overload
|
190
|
+
def select[Ts](self, selector: Optional[Callable[[T], Ts]] = None, *, flavour: Type[tuple], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[Ts, ...]: ...
|
191
|
+
@overload
|
192
|
+
def select[Ts](self, selector: Optional[Callable[[T], tuple[Ts]]] = None, *, flavour: Type[tuple], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[Ts, ...]: ...
|
193
|
+
@overload
|
194
|
+
def select[*Ts](self, selector: Optional[Callable[[T], tuple[*Ts]]] = None, *, flavour: Type[tuple], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[tuple[*Ts]]: ...
|
195
|
+
@overload
|
196
|
+
def select[TFlavour](self, selector: Optional[Callable[[T], tuple]] = None, *, flavour: Type[TFlavour], by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[TFlavour]: ...
|
197
|
+
@abstractmethod
|
198
|
+
def select[TValue, TFlavour, *Ts](self, selector: Optional[Callable[[T], tuple[TValue, *Ts]]] = lambda: None, *, flavour: Type[TFlavour] = None, by: JoinType = JoinType.INNER_JOIN): ...
|
199
|
+
|
200
|
+
# endregion
|
201
|
+
|
202
|
+
# region select_one
|
203
|
+
@overload
|
204
|
+
def select_one(self) -> T: ...
|
205
|
+
@overload
|
206
|
+
def select_one(self, *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[tuple]) -> tuple: ...
|
207
|
+
@overload
|
208
|
+
def select_one[T1](self, selector: Callable[[T], tuple[T1]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> T1: ...
|
209
|
+
@overload
|
210
|
+
def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = JoinType.INNER_JOIN) -> tuple[*Ts]: ...
|
211
|
+
@overload
|
212
|
+
def select_one[*Ts](self, selector: Callable[[T], tuple[*Ts]], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[tuple]) -> tuple[*Ts]: ...
|
213
|
+
@overload
|
214
|
+
def select_one[TFlavour](self, selector: Callable[[T], tuple], *, by: Optional[Enum] = JoinType.INNER_JOIN, flavour: Type[TFlavour]) -> TFlavour: ...
|
215
|
+
@abstractmethod
|
216
|
+
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): ...
|
217
|
+
|
218
|
+
# endregion
|
219
|
+
|
220
|
+
@abstractmethod
|
221
|
+
def build(self) -> str: ...
|
222
|
+
|
223
|
+
|
224
|
+
class IStatements_two_generic[T: Table, TRepo](IStatements[T]):
|
225
|
+
@property
|
226
|
+
@abstractmethod
|
227
|
+
def repository(self) -> IRepositoryBase[TRepo]: ...
|
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from abc import abstractmethod
|
2
|
+
|
3
|
+
from .IDelete import IDelete
|
4
|
+
from ...utils import Table
|
5
|
+
from ...common.interfaces import IRepositoryBase
|
6
|
+
from ...common.abstract_classes import NonQueryBase
|
7
|
+
|
8
|
+
|
9
|
+
class DeleteQueryBase[T: Table, TRepo: IRepositoryBase](NonQueryBase[T, TRepo], IDelete[T]):
|
10
|
+
def __init__(self, model: T, repository: TRepo) -> None:
|
11
|
+
super().__init__(model, repository)
|
12
|
+
|
13
|
+
@abstractmethod
|
14
|
+
def delete(self, instances: T | list[T]) -> None: ...
|
@@ -0,0 +1,21 @@
|
|
1
|
+
from abc import abstractmethod
|
2
|
+
from ...utils import Table
|
3
|
+
|
4
|
+
from .IInsert import IInsert
|
5
|
+
from ...common.interfaces import IRepositoryBase
|
6
|
+
from ...common.abstract_classes import NonQueryBase
|
7
|
+
|
8
|
+
|
9
|
+
class InsertQueryBase[T: Table, TRepo: IRepositoryBase](NonQueryBase[T, IRepositoryBase], IInsert[T]):
|
10
|
+
def __init__(self, model: T, repository: TRepo) -> None:
|
11
|
+
super().__init__(model, repository)
|
12
|
+
|
13
|
+
@abstractmethod
|
14
|
+
def insert(self, instances: T | list[T]) -> None: ...
|
15
|
+
|
16
|
+
@property
|
17
|
+
@abstractmethod
|
18
|
+
def CLAUSE(self) -> str: ...
|
19
|
+
|
20
|
+
@abstractmethod
|
21
|
+
def execute(self) -> None: ...
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from abc import abstractmethod
|
2
|
+
|
3
|
+
from ...common.interfaces import IQuery
|
4
|
+
from .table_column import TableColumn
|
5
|
+
|
6
|
+
|
7
|
+
class ISelect(IQuery):
|
8
|
+
@property
|
9
|
+
@abstractmethod
|
10
|
+
def select_list(self) -> list[TableColumn]: ...
|
11
|
+
|
12
|
+
@property
|
13
|
+
@abstractmethod
|
14
|
+
def tables_heritage(self) -> list[TableColumn]: ...
|
@@ -0,0 +1,39 @@
|
|
1
|
+
from typing import Any, Iterator
|
2
|
+
from ...utils import Table
|
3
|
+
|
4
|
+
|
5
|
+
class TableColumn:
|
6
|
+
def __init__(self, table: Table, col: str) -> None:
|
7
|
+
self._table: Table = table
|
8
|
+
self._column: str = col
|
9
|
+
|
10
|
+
def __repr__(self) -> str:
|
11
|
+
return f"{TableColumn.__name__}: T={self._table.__table_name__} col={self._column}"
|
12
|
+
|
13
|
+
@property
|
14
|
+
def real_column(self) -> str:
|
15
|
+
return self._column
|
16
|
+
|
17
|
+
@property
|
18
|
+
def column(self) -> str:
|
19
|
+
return f"{self._table.__table_name__}.{self._column} as `{self.alias}`"
|
20
|
+
|
21
|
+
@property
|
22
|
+
def alias(self) -> str:
|
23
|
+
return f"{self._table.__table_name__}_{self._column}"
|
24
|
+
|
25
|
+
def get_all_alias(self) -> list[str]:
|
26
|
+
return [class_.alias for class_ in self.all_columns(self._table)]
|
27
|
+
|
28
|
+
@classmethod
|
29
|
+
def all_columns(cls, table: Table) -> Iterator["TableColumn"]:
|
30
|
+
for col in table.__annotations__:
|
31
|
+
yield cls(table, col)
|
32
|
+
|
33
|
+
def __hash__(self) -> int:
|
34
|
+
return hash((self._table, self._column))
|
35
|
+
|
36
|
+
def __eq__(self, __value: Any) -> bool:
|
37
|
+
if isinstance(__value, TableColumn):
|
38
|
+
return self._table.__table_name__ == __value._table.__table_name__ and self._column == __value._column
|
39
|
+
return False
|
@@ -0,0 +1,25 @@
|
|
1
|
+
from abc import abstractmethod
|
2
|
+
from typing import Any, Optional
|
3
|
+
|
4
|
+
from .IUpdate import IUpdate
|
5
|
+
from ..where import AbstractWhere
|
6
|
+
from ...common.interfaces import IRepositoryBase
|
7
|
+
from ...common.abstract_classes import NonQueryBase
|
8
|
+
from ...utils import Table
|
9
|
+
|
10
|
+
|
11
|
+
class UpdateQueryBase[T: Table, TRepo: IRepositoryBase](NonQueryBase[T, TRepo], IUpdate):
|
12
|
+
def __init__(self, model: T, repository: TRepo, where: AbstractWhere = list[AbstractWhere]) -> None:
|
13
|
+
super().__init__(model, repository)
|
14
|
+
self._where: Optional[AbstractWhere] = where
|
15
|
+
|
16
|
+
@abstractmethod
|
17
|
+
def update(self, dicc: dict[str | property, Any]) -> None:
|
18
|
+
return super().update(dicc)
|
19
|
+
|
20
|
+
@property
|
21
|
+
@abstractmethod
|
22
|
+
def CLAUSE(self) -> str: ...
|
23
|
+
|
24
|
+
@abstractmethod
|
25
|
+
def execute(self) -> None: ...
|
@@ -0,0 +1,21 @@
|
|
1
|
+
from abc import abstractmethod
|
2
|
+
from .IUpsert import IUpsert
|
3
|
+
from ...common.interfaces import IRepositoryBase
|
4
|
+
from ...common.abstract_classes import NonQueryBase
|
5
|
+
|
6
|
+
from ...utils import Table
|
7
|
+
|
8
|
+
|
9
|
+
class UpsertQueryBase[T: Table, TRepo: IRepositoryBase](NonQueryBase[T, TRepo], IUpsert[T]):
|
10
|
+
def __init__(self, model: T, repository: TRepo) -> None:
|
11
|
+
super().__init__(model, repository)
|
12
|
+
|
13
|
+
@abstractmethod
|
14
|
+
def upsert(self, instances: T | list[T]) -> None: ...
|
15
|
+
|
16
|
+
@property
|
17
|
+
@abstractmethod
|
18
|
+
def CLAUSE(self) -> str: ...
|
19
|
+
|
20
|
+
@abstractmethod
|
21
|
+
def execute(self) -> None: ...
|
@@ -0,0 +1 @@
|
|
1
|
+
from .abstract_where import AbstractWhere # noqa: F401
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
from .create_database import CreateDatabase, TypeExists # noqa: F401
|
2
|
+
from .delete import DeleteQuery # noqa: F401
|
3
|
+
from .drop_database import DropDatabase # noqa: F401
|
4
|
+
from .drop_table import DropTable # noqa: F401
|
5
|
+
from .insert import InsertQuery # noqa: F401
|
6
|
+
from .joins import JoinSelector, JoinType # noqa: F401
|
7
|
+
from .limit import LimitQuery # noqa: F401
|
8
|
+
from .offset import OffsetQuery # noqa: F401
|
9
|
+
from .order import OrderQuery # noqa: F401
|
10
|
+
from .select import SelectQuery # noqa: F401
|
11
|
+
from .update import UpdateQuery # noqa: F401
|
12
|
+
from .upsert import UpsertQuery # noqa: F401
|
13
|
+
from .where_condition import WhereCondition # noqa: F401
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from typing import Literal, override
|
2
|
+
from mysql.connector import Error, errorcode
|
3
|
+
from mysql.connector import MySQLConnection
|
4
|
+
|
5
|
+
from ....common.interfaces import IRepositoryBase
|
6
|
+
|
7
|
+
TypeExists = Literal["fail", "replace", "append"]
|
8
|
+
|
9
|
+
|
10
|
+
class CreateDatabase:
|
11
|
+
def __init__(self, repository: IRepositoryBase[MySQLConnection]) -> None:
|
12
|
+
self._repository: IRepositoryBase[MySQLConnection] = repository
|
13
|
+
|
14
|
+
@override
|
15
|
+
@property
|
16
|
+
def CLAUSE(self) -> str:
|
17
|
+
return "CREATE DATABASE"
|
18
|
+
|
19
|
+
@override
|
20
|
+
def execute(self, name: str, if_exists: TypeExists = "fail") -> None:
|
21
|
+
with self._repository.connection.cursor() as cursor:
|
22
|
+
try:
|
23
|
+
cursor.execute(f"{self.CLAUSE} {name} DEFAULT CHARACTER SET 'utf8'")
|
24
|
+
except Error as err:
|
25
|
+
if err.errno == errorcode.ER_DB_CREATE_EXISTS and if_exists != "fail":
|
26
|
+
cursor.execute(f"USE {name};")
|
27
|
+
else:
|
28
|
+
raise err
|
29
|
+
return None
|
@@ -0,0 +1,54 @@
|
|
1
|
+
from typing import Any, override, Iterable
|
2
|
+
|
3
|
+
from ....utils import Table, Column
|
4
|
+
from ....common.interfaces import IRepositoryBase
|
5
|
+
from ....components.delete import DeleteQueryBase
|
6
|
+
from mysql.connector import MySQLConnection
|
7
|
+
|
8
|
+
|
9
|
+
class DeleteQuery[T: Table](DeleteQueryBase[T, IRepositoryBase[MySQLConnection]]):
|
10
|
+
def __init__(self, model: T, repository: IRepositoryBase[MySQLConnection]) -> None:
|
11
|
+
super().__init__(model, repository)
|
12
|
+
|
13
|
+
@property
|
14
|
+
def CLAUSE(self) -> str:
|
15
|
+
return "DELETE"
|
16
|
+
|
17
|
+
@override
|
18
|
+
def delete(self, instances: T | list[T]) -> None:
|
19
|
+
col: str = ""
|
20
|
+
if isinstance(instances, Table):
|
21
|
+
pk: Column = instances.get_pk()
|
22
|
+
if pk.column_value is None:
|
23
|
+
raise Exception(f"You cannot use 'DELETE' query without set primary key in '{instances.__table_name__}'")
|
24
|
+
col = pk.column_name
|
25
|
+
value = str(pk.column_value)
|
26
|
+
|
27
|
+
elif isinstance(instances, Iterable):
|
28
|
+
value: list[Any] = []
|
29
|
+
for ins in instances:
|
30
|
+
pk = ins.get_pk()
|
31
|
+
col = pk.column_name
|
32
|
+
value.append(pk.column_value)
|
33
|
+
|
34
|
+
query: str = f"{self.CLAUSE} FROM {self._model.__table_name__} WHERE {col}"
|
35
|
+
if isinstance(value, str):
|
36
|
+
query += "= %s"
|
37
|
+
self._query = query
|
38
|
+
self._values = [value]
|
39
|
+
return None
|
40
|
+
|
41
|
+
elif isinstance(value, Iterable):
|
42
|
+
params = ", ".join(["%s"] * len(value))
|
43
|
+
query += f" IN ({params})"
|
44
|
+
self._query = query
|
45
|
+
self._values = value
|
46
|
+
return None
|
47
|
+
else:
|
48
|
+
raise Exception(f"'{type(value)}' no esperado")
|
49
|
+
|
50
|
+
@override
|
51
|
+
def execute(self) -> None:
|
52
|
+
if not self._query:
|
53
|
+
raise ValueError
|
54
|
+
return self._repository.execute_with_values(self._query, self._values)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
from typing import override
|
2
|
+
from mysql.connector import MySQLConnection
|
3
|
+
|
4
|
+
|
5
|
+
from ....common.interfaces import IRepositoryBase
|
6
|
+
|
7
|
+
|
8
|
+
class DropDatabase:
|
9
|
+
def __init__(self, repository: IRepositoryBase[MySQLConnection]) -> None:
|
10
|
+
self._repository: IRepositoryBase[MySQLConnection] = repository
|
11
|
+
|
12
|
+
@override
|
13
|
+
def execute(self, name: str) -> None:
|
14
|
+
return self._repository.execute(f"{self.CLAUSE} {name}")
|
15
|
+
|
16
|
+
@override
|
17
|
+
@property
|
18
|
+
def CLAUSE(self) -> str:
|
19
|
+
return "DROP DATABASE IF EXISTS"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
from typing import Literal, override
|
2
|
+
|
3
|
+
from ....common.interfaces import IRepositoryBase
|
4
|
+
|
5
|
+
from mysql.connector import MySQLConnection
|
6
|
+
|
7
|
+
TypeExists = Literal["fail", "replace", "append"]
|
8
|
+
|
9
|
+
|
10
|
+
class DropTable:
|
11
|
+
def __init__(self, repository: IRepositoryBase[MySQLConnection]) -> None:
|
12
|
+
self._repository: IRepositoryBase[MySQLConnection] = repository
|
13
|
+
|
14
|
+
@override
|
15
|
+
def execute(self, name: str = None) -> None:
|
16
|
+
query = rf"{self.CLAUSE} {name}"
|
17
|
+
self._repository.execute(query)
|
18
|
+
return None
|
19
|
+
|
20
|
+
@property
|
21
|
+
@override
|
22
|
+
def CLAUSE(self) -> str:
|
23
|
+
return "DROP TABLE"
|
@@ -0,0 +1,70 @@
|
|
1
|
+
from typing import Any, override, Iterable
|
2
|
+
from mysql.connector import MySQLConnection
|
3
|
+
|
4
|
+
from ....utils import Table, Column
|
5
|
+
from ....components.insert import InsertQueryBase
|
6
|
+
from ....common.interfaces import IRepositoryBase
|
7
|
+
|
8
|
+
|
9
|
+
class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase[MySQLConnection]]):
|
10
|
+
def __init__(self, model: T, repository: IRepositoryBase[IRepositoryBase[MySQLConnection]]) -> None:
|
11
|
+
super().__init__(model, repository)
|
12
|
+
|
13
|
+
@override
|
14
|
+
@property
|
15
|
+
def CLAUSE(self) -> str:
|
16
|
+
return "INSERT INTO"
|
17
|
+
|
18
|
+
@override
|
19
|
+
def execute(self) -> None:
|
20
|
+
if not self._query:
|
21
|
+
raise ValueError
|
22
|
+
return self._repository.executemany_with_values(self.query, self._values)
|
23
|
+
|
24
|
+
@override
|
25
|
+
def insert(self, instances: T | list[T]) -> None:
|
26
|
+
new_dict_list: list[dict[str, Any]] = []
|
27
|
+
self.__fill_dict_list(new_dict_list, instances)
|
28
|
+
cols_tuple = new_dict_list[0].keys()
|
29
|
+
join_cols = ", ".join(cols_tuple)
|
30
|
+
unknown_rows = f'({", ".join(["%s"]*len(cols_tuple))})' # The number of "%s" must match the dict 'dicc_0' length
|
31
|
+
|
32
|
+
self._values = [tuple(x.values()) for x in new_dict_list]
|
33
|
+
self._query = f"{self.CLAUSE} {self._model.__table_name__} {f'({join_cols})'} VALUES {unknown_rows}"
|
34
|
+
return None
|
35
|
+
|
36
|
+
@staticmethod
|
37
|
+
def __is_valid(column: Column) -> bool:
|
38
|
+
"""
|
39
|
+
We want to delete the column from table when it's specified with an 'AUTO_INCREMENT' or 'AUTO GENERATED ALWAYS AS (__) STORED' statement.
|
40
|
+
|
41
|
+
if the column is auto-generated, it means the database creates the value for that column, so we must deleted it.
|
42
|
+
if the column is primary key and auto-increment, we should be able to create an object with specific pk value.
|
43
|
+
|
44
|
+
RETURN
|
45
|
+
-----
|
46
|
+
|
47
|
+
- True -> Do not delete the column from dict query
|
48
|
+
- False -> Delete the column from dict query
|
49
|
+
"""
|
50
|
+
|
51
|
+
is_pk_none_and_auto_increment: bool = all([column.column_value is None, column.is_primary_key, column.is_auto_increment])
|
52
|
+
|
53
|
+
if is_pk_none_and_auto_increment or column.is_auto_generated:
|
54
|
+
return False
|
55
|
+
return True
|
56
|
+
|
57
|
+
def __fill_dict_list(self, list_dict: list[dict], values: T | list[T]):
|
58
|
+
if issubclass(values.__class__, Table):
|
59
|
+
dicc: dict = {}
|
60
|
+
for col in values.__dict__.values():
|
61
|
+
if isinstance(col, Column) and self.__is_valid(col):
|
62
|
+
dicc.update({col.column_name: col.column_value})
|
63
|
+
list_dict.append(dicc)
|
64
|
+
return list_dict
|
65
|
+
|
66
|
+
elif isinstance(values, Iterable):
|
67
|
+
for x in values:
|
68
|
+
self.__fill_dict_list(list_dict, x)
|
69
|
+
else:
|
70
|
+
raise Exception(f"Tipo de dato'{type(values)}' no esperado")
|