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.
Files changed (70) hide show
  1. ormlambda/__init__.py +4 -0
  2. ormlambda/common/__init__.py +2 -0
  3. ormlambda/common/abstract_classes/__init__.py +3 -0
  4. ormlambda/common/abstract_classes/abstract_model.py +302 -0
  5. ormlambda/common/abstract_classes/non_query_base.py +33 -0
  6. ormlambda/common/abstract_classes/query_base.py +10 -0
  7. ormlambda/common/enums/__init__.py +2 -0
  8. ormlambda/common/enums/condition_types.py +16 -0
  9. ormlambda/common/enums/join_type.py +10 -0
  10. ormlambda/common/interfaces/INonQueryCommand.py +9 -0
  11. ormlambda/common/interfaces/IQueryCommand.py +11 -0
  12. ormlambda/common/interfaces/IRepositoryBase.py +67 -0
  13. ormlambda/common/interfaces/IStatements.py +227 -0
  14. ormlambda/common/interfaces/__init__.py +4 -0
  15. ormlambda/components/__init__.py +0 -0
  16. ormlambda/components/delete/IDelete.py +6 -0
  17. ormlambda/components/delete/__init__.py +2 -0
  18. ormlambda/components/delete/abstract_delete.py +14 -0
  19. ormlambda/components/insert/IInsert.py +6 -0
  20. ormlambda/components/insert/__init__.py +2 -0
  21. ormlambda/components/insert/abstract_insert.py +21 -0
  22. ormlambda/components/select/ISelect.py +14 -0
  23. ormlambda/components/select/__init__.py +2 -0
  24. ormlambda/components/select/table_column.py +39 -0
  25. ormlambda/components/update/IUpdate.py +7 -0
  26. ormlambda/components/update/__init__.py +2 -0
  27. ormlambda/components/update/abstract_update.py +25 -0
  28. ormlambda/components/upsert/IUpsert.py +6 -0
  29. ormlambda/components/upsert/__init__.py +2 -0
  30. ormlambda/components/upsert/abstract_upsert.py +21 -0
  31. ormlambda/components/where/__init__.py +1 -0
  32. ormlambda/components/where/abstract_where.py +11 -0
  33. ormlambda/databases/__init__.py +0 -0
  34. ormlambda/databases/my_sql/__init__.py +2 -0
  35. ormlambda/databases/my_sql/clauses/__init__.py +13 -0
  36. ormlambda/databases/my_sql/clauses/create_database.py +29 -0
  37. ormlambda/databases/my_sql/clauses/delete.py +54 -0
  38. ormlambda/databases/my_sql/clauses/drop_database.py +19 -0
  39. ormlambda/databases/my_sql/clauses/drop_table.py +23 -0
  40. ormlambda/databases/my_sql/clauses/insert.py +70 -0
  41. ormlambda/databases/my_sql/clauses/joins.py +103 -0
  42. ormlambda/databases/my_sql/clauses/limit.py +17 -0
  43. ormlambda/databases/my_sql/clauses/offset.py +17 -0
  44. ormlambda/databases/my_sql/clauses/order.py +29 -0
  45. ormlambda/databases/my_sql/clauses/select.py +172 -0
  46. ormlambda/databases/my_sql/clauses/update.py +52 -0
  47. ormlambda/databases/my_sql/clauses/upsert.py +68 -0
  48. ormlambda/databases/my_sql/clauses/where_condition.py +219 -0
  49. ormlambda/databases/my_sql/repository.py +192 -0
  50. ormlambda/databases/my_sql/statements.py +86 -0
  51. ormlambda/model_base.py +36 -0
  52. ormlambda/utils/__init__.py +3 -0
  53. ormlambda/utils/column.py +65 -0
  54. ormlambda/utils/dtypes.py +104 -0
  55. ormlambda/utils/foreign_key.py +36 -0
  56. ormlambda/utils/lambda_disassembler/__init__.py +4 -0
  57. ormlambda/utils/lambda_disassembler/dis_types.py +136 -0
  58. ormlambda/utils/lambda_disassembler/disassembler.py +69 -0
  59. ormlambda/utils/lambda_disassembler/dtypes.py +103 -0
  60. ormlambda/utils/lambda_disassembler/name_of.py +41 -0
  61. ormlambda/utils/lambda_disassembler/nested_element.py +44 -0
  62. ormlambda/utils/lambda_disassembler/tree_instruction.py +145 -0
  63. ormlambda/utils/module_tree/__init__.py +0 -0
  64. ormlambda/utils/module_tree/dfs_traversal.py +60 -0
  65. ormlambda/utils/module_tree/dynamic_module.py +237 -0
  66. ormlambda/utils/table_constructor.py +308 -0
  67. ormlambda-0.1.0.dist-info/LICENSE +21 -0
  68. ormlambda-0.1.0.dist-info/METADATA +268 -0
  69. ormlambda-0.1.0.dist-info/RECORD +70 -0
  70. 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]: ...
@@ -0,0 +1,4 @@
1
+ from .IQueryCommand import IQuery # noqa: F401
2
+ from .INonQueryCommand import INonQueryCommand # noqa: F401
3
+ from .IRepositoryBase import IRepositoryBase # noqa: F401
4
+ from .IStatements import IStatements,IStatements_two_generic # noqa: F401
File without changes
@@ -0,0 +1,6 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class IDelete[T](ABC):
5
+ @abstractmethod
6
+ def delete(self, instances: T | list[T]) -> None: ...
@@ -0,0 +1,2 @@
1
+ from .abstract_delete import DeleteQueryBase # noqa: F401
2
+ from .IDelete import IDelete # noqa: F401
@@ -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,6 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class IInsert[T](ABC):
5
+ @abstractmethod
6
+ def insert(self, instances: T | list[T])->None: ...
@@ -0,0 +1,2 @@
1
+ from .IInsert import IInsert # noqa: F401
2
+ from .abstract_insert import InsertQueryBase # noqa: F401
@@ -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,2 @@
1
+ from .ISelect import ISelect # noqa: F401
2
+ from .table_column import TableColumn # noqa: F401
@@ -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,7 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any
3
+
4
+
5
+ class IUpdate(ABC):
6
+ @abstractmethod
7
+ def update(self, dicc: dict[str|property, Any]) -> None: ...
@@ -0,0 +1,2 @@
1
+ from .abstract_update import UpdateQueryBase # noqa: F401
2
+ from .IUpdate import IUpdate # noqa: F401
@@ -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,6 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class IUpsert[T](ABC):
5
+ @abstractmethod
6
+ def upsert(self, instances: T | list[T]) -> None: ...
@@ -0,0 +1,2 @@
1
+ from .abstract_upsert import UpsertQueryBase # noqa: F401
2
+ from .IUpsert import IUpsert # noqa: F401
@@ -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
@@ -0,0 +1,11 @@
1
+ from abc import abstractmethod
2
+ from ...utils import Table
3
+
4
+ from ...common.interfaces import IQuery
5
+
6
+
7
+ class AbstractWhere(IQuery):
8
+ WHERE: str = "WHERE"
9
+
10
+ @abstractmethod
11
+ def get_involved_tables(self) -> tuple[tuple[Table, Table]]: ...
File without changes
@@ -0,0 +1,2 @@
1
+ from .repository import MySQLRepository, Error # noqa: F401
2
+ from .statements import MySQLStatements # noqa: F401
@@ -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")