ormlambda 1.5.0__py3-none-any.whl → 2.0.2__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 +9 -2
- ormlambda/common/__init__.py +0 -1
- ormlambda/common/abstract_classes/__init__.py +1 -1
- ormlambda/common/abstract_classes/abstract_model.py +13 -228
- ormlambda/common/abstract_classes/non_query_base.py +7 -5
- ormlambda/common/abstract_classes/query_base.py +5 -2
- ormlambda/common/enums/__init__.py +1 -1
- ormlambda/common/enums/join_type.py +2 -1
- ormlambda/common/interfaces/IQueryCommand.py +2 -1
- ormlambda/common/interfaces/IRepositoryBase.py +4 -18
- ormlambda/common/interfaces/IStatements.py +33 -15
- ormlambda/common/interfaces/__init__.py +1 -1
- ormlambda/components/delete/abstract_delete.py +6 -3
- ormlambda/components/insert/IInsert.py +1 -1
- ormlambda/components/insert/abstract_insert.py +8 -4
- ormlambda/components/select/ISelect.py +1 -1
- ormlambda/components/select/table_column.py +5 -1
- ormlambda/components/update/IUpdate.py +1 -1
- ormlambda/components/update/__init__.py +1 -1
- ormlambda/components/update/abstract_update.py +9 -5
- ormlambda/components/upsert/__init__.py +1 -1
- ormlambda/components/upsert/abstract_upsert.py +8 -4
- ormlambda/components/where/abstract_where.py +6 -2
- ormlambda/databases/my_sql/clauses/__init__.py +1 -0
- ormlambda/databases/my_sql/clauses/count.py +35 -0
- ormlambda/databases/my_sql/clauses/create_database.py +17 -10
- ormlambda/databases/my_sql/clauses/delete.py +7 -4
- ormlambda/databases/my_sql/clauses/drop_database.py +1 -1
- ormlambda/databases/my_sql/clauses/drop_table.py +1 -1
- ormlambda/databases/my_sql/clauses/insert.py +4 -3
- ormlambda/databases/my_sql/clauses/joins.py +8 -7
- ormlambda/databases/my_sql/clauses/limit.py +1 -1
- ormlambda/databases/my_sql/clauses/offset.py +1 -1
- ormlambda/databases/my_sql/clauses/order.py +3 -3
- ormlambda/databases/my_sql/clauses/select.py +5 -5
- ormlambda/databases/my_sql/clauses/update.py +3 -3
- ormlambda/databases/my_sql/clauses/upsert.py +3 -3
- ormlambda/databases/my_sql/clauses/where_condition.py +5 -5
- ormlambda/databases/my_sql/repository.py +57 -27
- ormlambda/databases/my_sql/statements.py +200 -43
- ormlambda/model_base.py +2 -4
- ormlambda/utils/column.py +4 -3
- ormlambda/utils/dtypes.py +6 -8
- ormlambda/utils/foreign_key.py +55 -10
- ormlambda/utils/lambda_disassembler/__init__.py +1 -1
- ormlambda/utils/lambda_disassembler/dis_types.py +22 -25
- ormlambda/utils/lambda_disassembler/tree_instruction.py +1 -1
- ormlambda/utils/module_tree/dynamic_module.py +6 -4
- ormlambda/utils/table_constructor.py +39 -22
- {ormlambda-1.5.0.dist-info → ormlambda-2.0.2.dist-info}/METADATA +13 -9
- ormlambda-2.0.2.dist-info/RECORD +71 -0
- ormlambda-1.5.0.dist-info/RECORD +0 -70
- {ormlambda-1.5.0.dist-info → ormlambda-2.0.2.dist-info}/LICENSE +0 -0
- {ormlambda-1.5.0.dist-info → ormlambda-2.0.2.dist-info}/WHEEL +0 -0
@@ -1,9 +1,13 @@
|
|
1
|
+
from __future__ import annotations
|
1
2
|
from abc import abstractmethod
|
2
|
-
from
|
3
|
-
|
4
|
-
|
3
|
+
from typing import TYPE_CHECKING
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from ormlambda import IRepositoryBase
|
7
|
+
from ormlambda import Table
|
5
8
|
|
6
|
-
from
|
9
|
+
from ormlambda.common.abstract_classes import NonQueryBase
|
10
|
+
from .IUpsert import IUpsert
|
7
11
|
|
8
12
|
|
9
13
|
class UpsertQueryBase[T: Table, TRepo: IRepositoryBase](NonQueryBase[T, TRepo], IUpsert[T]):
|
@@ -1,7 +1,11 @@
|
|
1
|
+
from __future__ import annotations
|
1
2
|
from abc import abstractmethod
|
2
|
-
from
|
3
|
+
from typing import TYPE_CHECKING
|
3
4
|
|
4
|
-
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
from ormlambda import Table
|
7
|
+
|
8
|
+
from ormlambda.common.interfaces import IQuery
|
5
9
|
|
6
10
|
|
7
11
|
class AbstractWhere(IQuery):
|
@@ -0,0 +1,35 @@
|
|
1
|
+
from typing import Callable, Type, override
|
2
|
+
|
3
|
+
from ormlambda import Table, JoinType, ForeignKey
|
4
|
+
from ormlambda.databases.my_sql.clauses.joins import JoinSelector
|
5
|
+
from ormlambda.databases.my_sql.clauses.select import SelectQuery
|
6
|
+
|
7
|
+
|
8
|
+
class CountQuery[T: Type[Table]](SelectQuery[T]):
|
9
|
+
CLAUSE: str = "COUNT"
|
10
|
+
|
11
|
+
def __init__(
|
12
|
+
self,
|
13
|
+
tables: T | tuple[T] = (),
|
14
|
+
select_lambda: Callable[[T], None] | None = lambda: None,
|
15
|
+
*,
|
16
|
+
by: JoinType = JoinType.INNER_JOIN,
|
17
|
+
) -> None:
|
18
|
+
super().__init__(tables, select_lambda, by=by)
|
19
|
+
|
20
|
+
@override
|
21
|
+
@property
|
22
|
+
def query(self) -> str:
|
23
|
+
query: str = f"{self.SELECT} {self.CLAUSE}(*) FROM {self._first_table.__table_name__}"
|
24
|
+
|
25
|
+
involved_tables = self.get_involved_tables()
|
26
|
+
if not involved_tables:
|
27
|
+
return query
|
28
|
+
|
29
|
+
sub_query: str = ""
|
30
|
+
for l_tbl, r_tbl in involved_tables:
|
31
|
+
join = JoinSelector(l_tbl, r_tbl, by=self._by, where=ForeignKey.MAPPED[l_tbl.__table_name__].referenced_tables[r_tbl.__table_name__].relationship)
|
32
|
+
sub_query += f" {join.query}"
|
33
|
+
|
34
|
+
query += sub_query
|
35
|
+
return query
|
@@ -1,8 +1,8 @@
|
|
1
1
|
from typing import Literal, override
|
2
|
-
from mysql.connector import
|
2
|
+
from mysql.connector import errorcode, errors
|
3
3
|
from mysql.connector import MySQLConnection
|
4
4
|
|
5
|
-
from
|
5
|
+
from ormlambda import IRepositoryBase
|
6
6
|
|
7
7
|
TypeExists = Literal["fail", "replace", "append"]
|
8
8
|
|
@@ -18,12 +18,19 @@ class CreateDatabase:
|
|
18
18
|
|
19
19
|
@override
|
20
20
|
def execute(self, name: str, if_exists: TypeExists = "fail") -> None:
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
if self._repository.database_exists(name):
|
22
|
+
if if_exists == "replace":
|
23
|
+
self._repository.drop_database(name)
|
24
|
+
elif if_exists == "fail":
|
25
|
+
raise errors.DatabaseError(msg=f"Database '{name}' already exists", errno=errorcode.ER_DB_CREATE_EXISTS)
|
26
|
+
elif if_exists == "append":
|
27
|
+
counter: int = 0
|
28
|
+
char: str = ""
|
29
|
+
while self._repository.database_exists(name + char):
|
30
|
+
counter += 1
|
31
|
+
char = f"_{counter}"
|
32
|
+
name += char
|
33
|
+
|
34
|
+
query = f"{self.CLAUSE} {name} DEFAULT CHARACTER SET 'utf8'"
|
35
|
+
self._repository.execute(query)
|
29
36
|
return None
|
@@ -1,8 +1,11 @@
|
|
1
|
-
from typing import Any, override, Iterable
|
1
|
+
from typing import Any, override, Iterable, TYPE_CHECKING
|
2
2
|
|
3
|
-
|
4
|
-
from
|
5
|
-
|
3
|
+
if TYPE_CHECKING:
|
4
|
+
from ormlambda import Column
|
5
|
+
|
6
|
+
from ormlambda import Table
|
7
|
+
from ormlambda import IRepositoryBase
|
8
|
+
from ormlambda.components.delete import DeleteQueryBase
|
6
9
|
from mysql.connector import MySQLConnection
|
7
10
|
|
8
11
|
|
@@ -1,9 +1,10 @@
|
|
1
1
|
from typing import Any, override, Iterable
|
2
2
|
from mysql.connector import MySQLConnection
|
3
3
|
|
4
|
-
from
|
5
|
-
from
|
6
|
-
from
|
4
|
+
from ormlambda import Table
|
5
|
+
from ormlambda import Column
|
6
|
+
from ormlambda.components.insert import InsertQueryBase
|
7
|
+
from ormlambda import IRepositoryBase
|
7
8
|
|
8
9
|
|
9
10
|
class InsertQuery[T: Table](InsertQueryBase[T, IRepositoryBase[MySQLConnection]]):
|
@@ -1,13 +1,14 @@
|
|
1
|
-
from
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import override, Callable, overload, Optional, TYPE_CHECKING
|
2
3
|
|
3
|
-
# from ..table import Table
|
4
4
|
|
5
|
-
from
|
6
|
-
from
|
7
|
-
from
|
5
|
+
from ormlambda.common.interfaces.IQueryCommand import IQuery
|
6
|
+
from ormlambda import Disassembler
|
7
|
+
from ormlambda import JoinType
|
8
8
|
|
9
|
-
# TODOL: Try to import Table module without circular import Error
|
10
|
-
|
9
|
+
# TODOL [x]: Try to import Table module without circular import Error
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from ormlambda import Table
|
11
12
|
|
12
13
|
|
13
14
|
class JoinSelector[TLeft, TRight](IQuery):
|
@@ -1,8 +1,8 @@
|
|
1
1
|
from typing import override, Callable
|
2
2
|
|
3
|
-
from
|
4
|
-
from
|
5
|
-
from
|
3
|
+
from ormlambda.utils.lambda_disassembler.tree_instruction import TreeInstruction
|
4
|
+
from ormlambda.common.interfaces.IQueryCommand import IQuery
|
5
|
+
from ormlambda.common.interfaces.IStatements import OrderType
|
6
6
|
|
7
7
|
ASC = "ASC"
|
8
8
|
DESC = "DESC"
|
@@ -1,10 +1,10 @@
|
|
1
1
|
from typing import Callable, Optional, Type, override
|
2
2
|
import inspect
|
3
3
|
|
4
|
-
from
|
5
|
-
from
|
6
|
-
from
|
7
|
-
from
|
4
|
+
from ormlambda.utils.lambda_disassembler import TreeInstruction, TupleInstruction, NestedElement
|
5
|
+
from ormlambda.components.select import ISelect, TableColumn
|
6
|
+
from ormlambda import Table, ForeignKey
|
7
|
+
from ormlambda.utils.table_constructor import TableMeta
|
8
8
|
|
9
9
|
from . import JoinSelector, JoinType
|
10
10
|
|
@@ -152,7 +152,7 @@ class SelectQuery[T: Table, *Ts](ISelect):
|
|
152
152
|
|
153
153
|
sub_query: str = ""
|
154
154
|
for l_tbl, r_tbl in involved_tables:
|
155
|
-
join = JoinSelector(l_tbl, r_tbl, by=self._by, where=ForeignKey.MAPPED[l_tbl][r_tbl])
|
155
|
+
join = JoinSelector(l_tbl, r_tbl, by=self._by, where=ForeignKey.MAPPED[l_tbl.__table_name__].referenced_tables[r_tbl.__table_name__].relationship)
|
156
156
|
sub_query += f" {join.query}"
|
157
157
|
|
158
158
|
query += sub_query
|
@@ -1,9 +1,9 @@
|
|
1
1
|
from typing import Type, override, Any
|
2
2
|
from mysql.connector import MySQLConnection
|
3
3
|
|
4
|
-
from
|
5
|
-
from
|
6
|
-
from
|
4
|
+
from ormlambda.components.update import UpdateQueryBase
|
5
|
+
from ormlambda import Table, Column
|
6
|
+
from ormlambda import IRepositoryBase
|
7
7
|
from .where_condition import WhereCondition
|
8
8
|
|
9
9
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
from typing import override, Any
|
2
2
|
|
3
|
-
from
|
4
|
-
from
|
5
|
-
from
|
3
|
+
from ormlambda import Table
|
4
|
+
from ormlambda.components.upsert import UpsertQueryBase
|
5
|
+
from ormlambda import IRepositoryBase
|
6
6
|
from mysql.connector import MySQLConnection
|
7
7
|
|
8
8
|
from .insert import InsertQuery
|
@@ -1,11 +1,11 @@
|
|
1
1
|
from typing import Any, Callable, Optional, override
|
2
2
|
import inspect
|
3
3
|
|
4
|
-
from
|
5
|
-
from
|
6
|
-
from
|
7
|
-
from
|
8
|
-
from
|
4
|
+
from ormlambda.common.enums import ConditionType
|
5
|
+
from ormlambda.utils.lambda_disassembler.tree_instruction import TreeInstruction, TupleInstruction
|
6
|
+
from ormlambda.common.interfaces.IQueryCommand import IQuery
|
7
|
+
from ormlambda.components.where.abstract_where import AbstractWhere
|
8
|
+
from ormlambda import Table
|
9
9
|
|
10
10
|
|
11
11
|
class WhereConditionByArg[TProp1, TProp2](IQuery):
|
@@ -1,14 +1,15 @@
|
|
1
|
-
|
1
|
+
from __future__ import annotations
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import Any, Type, override
|
4
|
-
|
3
|
+
from typing import Any, Optional, Type, override, Callable
|
4
|
+
import functools
|
5
5
|
|
6
6
|
# from mysql.connector.pooling import MySQLConnectionPool
|
7
7
|
from mysql.connector import MySQLConnection, Error # noqa: F401
|
8
|
+
from mysql.connector.pooling import PooledMySQLConnection, MySQLConnectionPool # noqa: F401
|
8
9
|
|
9
10
|
# Custom libraries
|
10
|
-
from
|
11
|
-
from
|
11
|
+
from ormlambda import IRepositoryBase
|
12
|
+
from ormlambda.utils.module_tree.dynamic_module import ModuleTree
|
12
13
|
|
13
14
|
from .clauses import CreateDatabase, TypeExists
|
14
15
|
from .clauses import DropDatabase
|
@@ -51,39 +52,66 @@ class Response[TFlavour, *Ts]:
|
|
51
52
|
def _tuple() -> list[tuple[*Ts]]:
|
52
53
|
return data
|
53
54
|
|
55
|
+
def _set() -> list[set]:
|
56
|
+
for d in data:
|
57
|
+
n = len(d)
|
58
|
+
for i in range(n):
|
59
|
+
try:
|
60
|
+
hash(d[i])
|
61
|
+
except TypeError:
|
62
|
+
raise TypeError(f"unhashable type '{type(d[i])}' found in '{type(d)}' when attempting to cast the result into a '{set.__name__}' object")
|
63
|
+
return [set(x) for x in data]
|
64
|
+
|
54
65
|
def _default() -> list[TFlavour]:
|
55
66
|
return [self._flavour(x, **self._kwargs) for x in data]
|
56
67
|
|
57
|
-
selector: dict[Type[object], Any] = {
|
68
|
+
selector: dict[Type[object], Any] = {
|
69
|
+
dict: _dict,
|
70
|
+
tuple: _tuple,
|
71
|
+
set: _set,
|
72
|
+
}
|
58
73
|
|
59
74
|
return selector.get(self._flavour, _default)()
|
60
75
|
|
61
76
|
|
62
77
|
class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
78
|
+
def get_connection(func: Callable[..., Any]):
|
79
|
+
@functools.wraps(func)
|
80
|
+
def wrapper(self: IRepositoryBase[MySQLConnection], *args, **kwargs):
|
81
|
+
self.connect()
|
82
|
+
try:
|
83
|
+
foo = func(self, *args, **kwargs)
|
84
|
+
finally:
|
85
|
+
self.connection.rollback()
|
86
|
+
self.close_connection()
|
87
|
+
return foo
|
88
|
+
|
89
|
+
return wrapper
|
90
|
+
|
63
91
|
def __init__(self, **kwargs: Any) -> None:
|
64
92
|
self._data_config: dict[str, Any] = kwargs
|
65
|
-
self.
|
66
|
-
|
67
|
-
pass
|
93
|
+
self._pool: MySQLConnectionPool = self.__create_MySQLConnectionPool()
|
94
|
+
self._connection: PooledMySQLConnection = None
|
68
95
|
|
96
|
+
def __create_MySQLConnectionPool(self):
|
97
|
+
return MySQLConnectionPool(pool_name="mypool",pool_size=10, **self._data_config)
|
69
98
|
@override
|
70
99
|
def is_connected(self) -> bool:
|
71
|
-
return self._connection.
|
100
|
+
return self._connection._cnx is not None if self._connection else False
|
72
101
|
|
73
102
|
@override
|
74
|
-
def connect(self) ->
|
75
|
-
|
76
|
-
self._connection.connect(**self._data_config)
|
103
|
+
def connect(self) -> None:
|
104
|
+
self._connection = self._pool.get_connection()
|
77
105
|
return None
|
78
106
|
|
79
107
|
@override
|
80
108
|
def close_connection(self) -> None:
|
81
|
-
if self.
|
109
|
+
if self.is_connected():
|
82
110
|
self._connection.close()
|
83
111
|
return None
|
84
112
|
|
85
113
|
@override
|
86
|
-
@
|
114
|
+
@get_connection
|
87
115
|
def read_sql[TFlavour](self, query: str, flavour: Type[TFlavour] = tuple, **kwargs) -> tuple[TFlavour]:
|
88
116
|
"""
|
89
117
|
Return tuple of tuples by default.
|
@@ -101,7 +129,7 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
101
129
|
return Response[TFlavour](response_values=values, columns=columns, flavour=flavour, **kwargs).response
|
102
130
|
|
103
131
|
# FIXME [ ]: this method does not comply with the implemented interface
|
104
|
-
@
|
132
|
+
@get_connection
|
105
133
|
def create_tables_code_first(self, path: str | Path) -> None:
|
106
134
|
if not isinstance(path, Path | str):
|
107
135
|
raise ValueError
|
@@ -123,7 +151,7 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
123
151
|
return None
|
124
152
|
|
125
153
|
@override
|
126
|
-
@
|
154
|
+
@get_connection
|
127
155
|
def executemany_with_values(self, query: str, values) -> None:
|
128
156
|
with self._connection.cursor(buffered=True) as cursor:
|
129
157
|
cursor.executemany(query, values)
|
@@ -131,7 +159,7 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
131
159
|
return None
|
132
160
|
|
133
161
|
@override
|
134
|
-
@
|
162
|
+
@get_connection
|
135
163
|
def execute_with_values(self, query: str, values) -> None:
|
136
164
|
with self._connection.cursor(buffered=True) as cursor:
|
137
165
|
cursor.execute(query, values)
|
@@ -139,7 +167,7 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
139
167
|
return None
|
140
168
|
|
141
169
|
@override
|
142
|
-
@
|
170
|
+
@get_connection
|
143
171
|
def execute(self, query: str) -> None:
|
144
172
|
with self._connection.cursor(buffered=True) as cursor:
|
145
173
|
cursor.execute(query)
|
@@ -147,12 +175,11 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
147
175
|
return None
|
148
176
|
|
149
177
|
@override
|
150
|
-
@IRepositoryBase.check_connection
|
151
178
|
def drop_table(self, name: str) -> None:
|
152
179
|
return DropTable(self).execute(name)
|
153
180
|
|
154
181
|
@override
|
155
|
-
@
|
182
|
+
@get_connection
|
156
183
|
def database_exists(self, name: str) -> bool:
|
157
184
|
query = "SHOW DATABASES LIKE %s;"
|
158
185
|
with self._connection.cursor(buffered=True) as cursor:
|
@@ -161,12 +188,11 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
161
188
|
return len(res) > 0
|
162
189
|
|
163
190
|
@override
|
164
|
-
@IRepositoryBase.check_connection
|
165
191
|
def drop_database(self, name: str) -> None:
|
166
192
|
return DropDatabase(self).execute(name)
|
167
193
|
|
168
194
|
@override
|
169
|
-
@
|
195
|
+
@get_connection
|
170
196
|
def table_exists(self, name: str) -> bool:
|
171
197
|
if not self._connection.database:
|
172
198
|
raise Exception("No database selected")
|
@@ -178,7 +204,6 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
178
204
|
return len(res) > 0
|
179
205
|
|
180
206
|
@override
|
181
|
-
@IRepositoryBase.check_connection
|
182
207
|
def create_database(self, name: str, if_exists: TypeExists = "fail") -> None:
|
183
208
|
return CreateDatabase(self).execute(name, if_exists)
|
184
209
|
|
@@ -187,6 +212,11 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
187
212
|
def connection(self) -> MySQLConnection:
|
188
213
|
return self._connection
|
189
214
|
|
190
|
-
@
|
191
|
-
def
|
192
|
-
return self._data_config.
|
215
|
+
@property
|
216
|
+
def database(self) -> Optional[str]:
|
217
|
+
return self._data_config.get("database", None)
|
218
|
+
|
219
|
+
@database.setter
|
220
|
+
def database(self, value: str) -> None:
|
221
|
+
self._data_config["database"] = value
|
222
|
+
self._pool = self.__create_MySQLConnectionPool()
|