ormlambda 1.0.1__py3-none-any.whl → 1.1.3__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 +8 -2
- ormlambda/common/__init__.py +0 -1
- ormlambda/common/abstract_classes/__init__.py +1 -1
- ormlambda/common/abstract_classes/abstract_model.py +30 -13
- 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/IStatements.py +25 -14
- 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 +26 -4
- ormlambda/databases/my_sql/statements.py +14 -5
- ormlambda/model_base.py +0 -2
- ormlambda/utils/column.py +4 -3
- ormlambda/utils/dtypes.py +2 -17
- 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.0.1.dist-info → ormlambda-1.1.3.dist-info}/METADATA +8 -8
- ormlambda-1.1.3.dist-info/RECORD +71 -0
- ormlambda-1.0.1.dist-info/RECORD +0 -70
- {ormlambda-1.0.1.dist-info → ormlambda-1.1.3.dist-info}/LICENSE +0 -0
- {ormlambda-1.0.1.dist-info → ormlambda-1.1.3.dist-info}/WHEEL +0 -0
@@ -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,14 @@
|
|
1
1
|
# Standard libraries
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import Any, Type, override
|
3
|
+
from typing import Any, Optional, Type, override
|
4
4
|
|
5
5
|
|
6
6
|
# from mysql.connector.pooling import MySQLConnectionPool
|
7
7
|
from mysql.connector import MySQLConnection, Error # noqa: F401
|
8
8
|
|
9
9
|
# Custom libraries
|
10
|
-
from
|
11
|
-
from
|
10
|
+
from ormlambda import IRepositoryBase
|
11
|
+
from ormlambda.utils.module_tree.dynamic_module import ModuleTree
|
12
12
|
|
13
13
|
from .clauses import CreateDatabase, TypeExists
|
14
14
|
from .clauses import DropDatabase
|
@@ -51,10 +51,24 @@ class Response[TFlavour, *Ts]:
|
|
51
51
|
def _tuple() -> list[tuple[*Ts]]:
|
52
52
|
return data
|
53
53
|
|
54
|
+
def _set() -> list[set]:
|
55
|
+
for d in data:
|
56
|
+
n = len(d)
|
57
|
+
for i in range(n):
|
58
|
+
try:
|
59
|
+
hash(d[i])
|
60
|
+
except TypeError:
|
61
|
+
raise TypeError(f"unhashable type '{type(d[i])}' found in '{type(d)}' when attempting to cast the result into a '{set.__name__}' object")
|
62
|
+
return [set(x) for x in data]
|
63
|
+
|
54
64
|
def _default() -> list[TFlavour]:
|
55
65
|
return [self._flavour(x, **self._kwargs) for x in data]
|
56
66
|
|
57
|
-
selector: dict[Type[object], Any] = {
|
67
|
+
selector: dict[Type[object], Any] = {
|
68
|
+
dict: _dict,
|
69
|
+
tuple: _tuple,
|
70
|
+
set: _set,
|
71
|
+
}
|
58
72
|
|
59
73
|
return selector.get(self._flavour, _default)()
|
60
74
|
|
@@ -190,3 +204,11 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
|
|
190
204
|
@override
|
191
205
|
def set_config(self, value: dict[str, Any]) -> dict[str, Any]:
|
192
206
|
return self._data_config.update(value)
|
207
|
+
|
208
|
+
@property
|
209
|
+
def database(self) -> Optional[str]:
|
210
|
+
return self._data_config.get("database", None)
|
211
|
+
|
212
|
+
@database.setter
|
213
|
+
def database(self, value: str) -> None:
|
214
|
+
self._data_config["database"] = value
|
@@ -1,10 +1,13 @@
|
|
1
|
-
from
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import override, Type, TYPE_CHECKING
|
2
3
|
|
4
|
+
if TYPE_CHECKING:
|
5
|
+
from ormlambda import Table
|
6
|
+
from ormlambda.components.select import ISelect
|
3
7
|
|
4
|
-
from
|
5
|
-
|
6
|
-
from
|
7
|
-
from ...components.select import ISelect
|
8
|
+
from ormlambda.common.abstract_classes import AbstractSQLStatements
|
9
|
+
|
10
|
+
from ormlambda.common.interfaces import IQuery, IRepositoryBase
|
8
11
|
|
9
12
|
from .clauses import DeleteQuery
|
10
13
|
from .clauses import InsertQuery
|
@@ -16,6 +19,7 @@ from .clauses import SelectQuery
|
|
16
19
|
from .clauses import UpsertQuery
|
17
20
|
from .clauses import UpdateQuery
|
18
21
|
from .clauses import WhereCondition
|
22
|
+
from .clauses import CountQuery
|
19
23
|
|
20
24
|
from mysql.connector import MySQLConnection
|
21
25
|
|
@@ -60,6 +64,11 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
|
|
60
64
|
def OFFSET_QUERY(self) -> Type[IQuery]:
|
61
65
|
return OffsetQuery
|
62
66
|
|
67
|
+
@property
|
68
|
+
@override
|
69
|
+
def COUNT(self) -> int:
|
70
|
+
return CountQuery
|
71
|
+
|
63
72
|
@property
|
64
73
|
@override
|
65
74
|
def JOIN_QUERY(self) -> Type[IQuery]:
|
ormlambda/model_base.py
CHANGED
ormlambda/utils/column.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from typing import Type
|
2
2
|
|
3
|
+
|
3
4
|
class Column[T]:
|
4
5
|
__slots__ = (
|
5
6
|
"dtype",
|
@@ -13,7 +14,7 @@ class Column[T]:
|
|
13
14
|
|
14
15
|
def __init__(
|
15
16
|
self,
|
16
|
-
dtype:Type[T] = None,
|
17
|
+
dtype: Type[T] = None,
|
17
18
|
column_name: str = None,
|
18
19
|
column_value: T = None,
|
19
20
|
*,
|
@@ -35,9 +36,9 @@ class Column[T]:
|
|
35
36
|
|
36
37
|
def __to_string__(self, name: str, var_name: T, type_: str):
|
37
38
|
dicc: dict = {
|
38
|
-
"dtype":type_,
|
39
|
+
"dtype": type_,
|
39
40
|
"column_name": f"'{name}'",
|
40
|
-
"column_value": var_name,
|
41
|
+
"column_value": var_name, # must be the same variable name as the instance variable name in Table's __init__ class
|
41
42
|
}
|
42
43
|
exec_str: str = f"{Column.__name__}[{type_}]("
|
43
44
|
for x in self.__slots__:
|
ormlambda/utils/dtypes.py
CHANGED
@@ -49,7 +49,7 @@ MySQL 8.0 does not support year in two-digit format.
|
|
49
49
|
|
50
50
|
from decimal import Decimal
|
51
51
|
import datetime
|
52
|
-
from typing import Any,Literal
|
52
|
+
from typing import Any, Literal
|
53
53
|
import numpy as np
|
54
54
|
|
55
55
|
from .column import Column
|
@@ -61,31 +61,16 @@ NUMERIC_UNSIGNED = Literal["BIT(size)", "TINYINT(size)", "BOOL", "BOOLEAN", "SMA
|
|
61
61
|
DATE = Literal["DATE", "DATETIME(fsp)", "TIMESTAMP(fsp)", "TIME(fsp)", "YEAR"]
|
62
62
|
|
63
63
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
64
|
# FIXME [ ]: this method does not comply with the implemented interface; we need to adjust it in the future to scale it to other databases
|
69
65
|
@staticmethod
|
70
66
|
def transform_py_dtype_into_query_dtype(dtype: Any) -> str:
|
71
67
|
# TODOL: must be found a better way to convert python data type into SQL clauses
|
72
68
|
# float -> DECIMAL(5,2) is an error
|
73
|
-
dicc: dict[Any, str] = {
|
74
|
-
int: "INTEGER",
|
75
|
-
float: "FLOAT(5,2)",
|
76
|
-
Decimal: "FLOAT",
|
77
|
-
datetime.datetime: "DATETIME",
|
78
|
-
datetime.date: "DATE",
|
79
|
-
bytes: "BLOB",
|
80
|
-
str: "VARCHAR(255)",
|
81
|
-
np.uint64: "BIGINT UNSIGNED"
|
82
|
-
}
|
69
|
+
dicc: dict[Any, str] = {int: "INTEGER", float: "FLOAT(5,2)", Decimal: "FLOAT", datetime.datetime: "DATETIME", datetime.date: "DATE", bytes: "BLOB", str: "VARCHAR(255)", np.uint64: "BIGINT UNSIGNED"}
|
83
70
|
|
84
71
|
return dicc[dtype]
|
85
72
|
|
86
73
|
|
87
|
-
|
88
|
-
|
89
74
|
# FIXME [ ]: this method does not comply with the implemented interface; we need to adjust it in the future to scale it to other databases
|
90
75
|
def get_query_clausule(column_obj: Column) -> str:
|
91
76
|
dtype: str = transform_py_dtype_into_query_dtype(column_obj.dtype)
|
ormlambda/utils/foreign_key.py
CHANGED
@@ -1,13 +1,51 @@
|
|
1
|
-
from
|
2
|
-
from typing import Callable, TYPE_CHECKING, Type
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import Callable, TYPE_CHECKING, NamedTuple, Type, Optional, overload
|
3
3
|
from .lambda_disassembler import Disassembler
|
4
4
|
|
5
5
|
if TYPE_CHECKING:
|
6
6
|
from .table_constructor import Table
|
7
7
|
|
8
8
|
|
9
|
-
class
|
10
|
-
|
9
|
+
class ReferencedTable[T1: Type[Table], T2: Type[Table]](NamedTuple):
|
10
|
+
obj: T2
|
11
|
+
relationship: Callable[[T1, T2], bool]
|
12
|
+
|
13
|
+
|
14
|
+
class TableInfo[T1: Type[Table], T2: Type[Table]]:
|
15
|
+
@overload
|
16
|
+
def __init__(self) -> None: ...
|
17
|
+
@overload
|
18
|
+
def __init__(self, table_object: T1) -> None: ...
|
19
|
+
|
20
|
+
def __init__(self, table_object: Optional[T1] = None) -> None:
|
21
|
+
self._table_object: Optional[T1] = table_object
|
22
|
+
self._referenced_tables: dict[str, ReferencedTable[T1, T2]] = {}
|
23
|
+
|
24
|
+
def __repr__(self) -> str:
|
25
|
+
return f"<{TableInfo.__name__}> class '{self.table_object}' dependent tables -> [{', '.join(tuple(self.referenced_tables))}]"
|
26
|
+
|
27
|
+
@property
|
28
|
+
def referenced_tables(self) -> dict[str, ReferencedTable[T1, T2]]:
|
29
|
+
return self._referenced_tables
|
30
|
+
|
31
|
+
def update_referenced_tables(self, referenced_table: Type[Table], relationship: Callable[[T1, T2], bool]) -> None:
|
32
|
+
self._referenced_tables.update({referenced_table.__table_name__: ReferencedTable[T1, T2](referenced_table, relationship)})
|
33
|
+
|
34
|
+
@property
|
35
|
+
def table_object(self) -> Optional[Type[Table]]:
|
36
|
+
return self._table_object
|
37
|
+
|
38
|
+
@table_object.setter
|
39
|
+
def table_object(self, value: Type[Table]) -> None:
|
40
|
+
self._table_object = value
|
41
|
+
|
42
|
+
@property
|
43
|
+
def has_relationship(self) -> bool:
|
44
|
+
return len(self._referenced_tables) > 0
|
45
|
+
|
46
|
+
|
47
|
+
class ForeignKey[Tbl1: Type[Table], Tbl2: Type[Table]]:
|
48
|
+
MAPPED: dict[str, TableInfo[Tbl1, Tbl2]] = {}
|
11
49
|
|
12
50
|
def __new__(
|
13
51
|
cls,
|
@@ -20,17 +58,24 @@ class ForeignKey[Tbl1:Table, Tbl2:Table]:
|
|
20
58
|
return referenced_table
|
21
59
|
|
22
60
|
@classmethod
|
23
|
-
def add_foreign_key(cls, orig_table: str, referenced_table:
|
24
|
-
cls.MAPPED
|
61
|
+
def add_foreign_key(cls, orig_table: str, referenced_table: Table, relationship: Callable[[Tbl1, Tbl2], bool]) -> None:
|
62
|
+
if orig_table not in cls.MAPPED:
|
63
|
+
cls.MAPPED[orig_table] = TableInfo()
|
64
|
+
|
65
|
+
# if referenced_table not in cls.MAPPED[orig_table]:
|
66
|
+
cls.MAPPED[orig_table].update_referenced_tables(referenced_table, relationship)
|
67
|
+
|
25
68
|
return None
|
26
69
|
|
27
70
|
@classmethod
|
28
|
-
def create_query(cls, orig_table:
|
71
|
+
def create_query(cls, orig_table: Table) -> list[str]:
|
29
72
|
clauses: list[str] = []
|
30
|
-
|
31
|
-
|
73
|
+
|
74
|
+
fk: TableInfo[Tbl1, Tbl2] = ForeignKey[Tbl1, Tbl2].MAPPED[orig_table.__table_name__]
|
75
|
+
for referenced_table_obj in fk.referenced_tables.values():
|
76
|
+
dissambler: Disassembler = Disassembler(referenced_table_obj.relationship)
|
32
77
|
orig_col: str = dissambler.cond_1.name
|
33
78
|
referenced_col: str = dissambler.cond_2.name
|
34
79
|
|
35
|
-
clauses.append(f"FOREIGN KEY ({orig_col}) REFERENCES {
|
80
|
+
clauses.append(f"FOREIGN KEY ({orig_col}) REFERENCES {referenced_table_obj.obj.__table_name__}({referenced_col})")
|
36
81
|
return clauses
|
@@ -1,4 +1,4 @@
|
|
1
1
|
from .disassembler import Disassembler # noqa: F401
|
2
2
|
from .nested_element import NestedElement # noqa: F401
|
3
3
|
from .tree_instruction import TreeInstruction, TupleInstruction # noqa: F401
|
4
|
-
from .name_of import nameof # noqa: F401
|
4
|
+
from .name_of import nameof # noqa: F401
|
@@ -1,9 +1,6 @@
|
|
1
1
|
from enum import Enum
|
2
2
|
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
4
|
class OpName(Enum):
|
8
5
|
CACHE = "CACHE"
|
9
6
|
POP_TOP = "POP_TOP"
|
@@ -112,25 +109,25 @@ class OpName(Enum):
|
|
112
109
|
INSTRUMENTED_END_SEND = "INSTRUMENTED_END_SEND"
|
113
110
|
INSTRUMENTED_INSTRUCTION = "INSTRUMENTED_INSTRUCTION"
|
114
111
|
INSTRUMENTED_LINE = "INSTRUMENTED_LINE"
|
115
|
-
FOR_ITER=
|
116
|
-
JUMP_FORWARD=
|
117
|
-
POP_JUMP_IF_FALSE=
|
118
|
-
POP_JUMP_IF_TRUE=
|
119
|
-
SEND=
|
120
|
-
POP_JUMP_IF_NOT_NONE=
|
121
|
-
POP_JUMP_IF_NONE=
|
122
|
-
JUMP_BACKWARD_NO_INTERRUPT=
|
123
|
-
JUMP_BACKWARD=
|
124
|
-
STORE_NAME=
|
125
|
-
DELETE_NAME=
|
126
|
-
STORE_ATTR=
|
127
|
-
DELETE_ATTR=
|
128
|
-
STORE_GLOBAL=
|
129
|
-
DELETE_GLOBAL=
|
130
|
-
LOAD_NAME=
|
131
|
-
LOAD_ATTR=
|
132
|
-
IMPORT_NAME=
|
133
|
-
IMPORT_FROM=
|
134
|
-
LOAD_GLOBAL=
|
135
|
-
LOAD_SUPER_ATTR=
|
136
|
-
LOAD_FROM_DICT_OR_GLOBALS=
|
112
|
+
FOR_ITER = "FOR_ITER"
|
113
|
+
JUMP_FORWARD = "JUMP_FORWARD"
|
114
|
+
POP_JUMP_IF_FALSE = "POP_JUMP_IF_FALSE"
|
115
|
+
POP_JUMP_IF_TRUE = "POP_JUMP_IF_TRUE"
|
116
|
+
SEND = "SEND"
|
117
|
+
POP_JUMP_IF_NOT_NONE = "POP_JUMP_IF_NOT_NONE"
|
118
|
+
POP_JUMP_IF_NONE = "POP_JUMP_IF_NONE"
|
119
|
+
JUMP_BACKWARD_NO_INTERRUPT = "JUMP_BACKWARD_NO_INTERRUPT"
|
120
|
+
JUMP_BACKWARD = "JUMP_BACKWARD"
|
121
|
+
STORE_NAME = "STORE_NAME"
|
122
|
+
DELETE_NAME = "DELETE_NAME"
|
123
|
+
STORE_ATTR = "STORE_ATTR"
|
124
|
+
DELETE_ATTR = "DELETE_ATTR"
|
125
|
+
STORE_GLOBAL = "STORE_GLOBAL"
|
126
|
+
DELETE_GLOBAL = "DELETE_GLOBAL"
|
127
|
+
LOAD_NAME = "LOAD_NAME"
|
128
|
+
LOAD_ATTR = "LOAD_ATTR"
|
129
|
+
IMPORT_NAME = "IMPORT_NAME"
|
130
|
+
IMPORT_FROM = "IMPORT_FROM"
|
131
|
+
LOAD_GLOBAL = "LOAD_GLOBAL"
|
132
|
+
LOAD_SUPER_ATTR = "LOAD_SUPER_ATTR"
|
133
|
+
LOAD_FROM_DICT_OR_GLOBALS = "LOAD_FROM_DICT_OR_GLOBALS"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from collections import defaultdict
|
2
2
|
from typing import Any, Callable, NamedTuple, Self, Optional
|
3
3
|
from dis import Instruction, Bytecode
|
4
|
-
from
|
4
|
+
from ormlambda.common.enums.condition_types import ConditionType
|
5
5
|
from .dis_types import OpName
|
6
6
|
from .nested_element import NestedElement
|
7
7
|
|
@@ -6,7 +6,9 @@ import importlib.util
|
|
6
6
|
import inspect
|
7
7
|
import re
|
8
8
|
|
9
|
-
from
|
9
|
+
from ormlambda import ForeignKey
|
10
|
+
|
11
|
+
from ormlambda import Table
|
10
12
|
from .dfs_traversal import DFSTraversal
|
11
13
|
|
12
14
|
|
@@ -180,12 +182,12 @@ class ModuleTree:
|
|
180
182
|
"""
|
181
183
|
tables: list[tuple[str, Table]] = self.get_member_table(self.load_module("", self.module_path))
|
182
184
|
|
183
|
-
graph: dict[
|
185
|
+
graph: dict[str, list[str]] = defaultdict(list)
|
184
186
|
for _, tbl in tables:
|
185
|
-
graph[tbl] = tbl.find_dependent_tables()
|
187
|
+
graph[tbl.__table_name__] = [x.__table_name__ for x in tbl.find_dependent_tables()]
|
186
188
|
|
187
189
|
sorted_tables = DFSTraversal.sort(graph)
|
188
|
-
res = [x.create_table_query() for x in sorted_tables]
|
190
|
+
res = [ForeignKey.MAPPED[x].table_object.create_table_query() for x in sorted_tables]
|
189
191
|
return res
|
190
192
|
|
191
193
|
@staticmethod
|
@@ -1,5 +1,4 @@
|
|
1
1
|
import base64
|
2
|
-
from collections import defaultdict
|
3
2
|
import datetime
|
4
3
|
from decimal import Decimal
|
5
4
|
from typing import Any, Iterable, Optional, Type, dataclass_transform
|
@@ -9,7 +8,7 @@ from .dtypes import get_query_clausule
|
|
9
8
|
from .module_tree.dfs_traversal import DFSTraversal
|
10
9
|
from .column import Column
|
11
10
|
|
12
|
-
from .foreign_key import ForeignKey
|
11
|
+
from .foreign_key import ForeignKey, TableInfo
|
13
12
|
|
14
13
|
MISSING = Column()
|
15
14
|
|
@@ -156,7 +155,7 @@ class TableMeta(type):
|
|
156
155
|
if not isinstance(cls_object.__table_name__, str):
|
157
156
|
raise Exception(f"class variable '__table_name__' of '{cls_object.__name__}' class must be 'str'")
|
158
157
|
|
159
|
-
TableMeta.
|
158
|
+
TableMeta.__add_to_ForeignKey(cls_object)
|
160
159
|
self = __init_constructor__(cls_object)
|
161
160
|
return self
|
162
161
|
|
@@ -164,14 +163,17 @@ class TableMeta(type):
|
|
164
163
|
return f"{TableMeta.__name__}: {cls.__table_name__}"
|
165
164
|
|
166
165
|
@staticmethod
|
167
|
-
def
|
166
|
+
def __add_to_ForeignKey(cls: "Table") -> None:
|
168
167
|
"""
|
169
168
|
When creating a Table class, we cannot pass the class itself as a parameter in a function that initializes a class variable.
|
170
|
-
To fix this, we first add the table name and then,
|
169
|
+
To fix this, we first add the table name as key and then, we add the class itself in the TableInfo class.
|
171
170
|
"""
|
172
|
-
if
|
173
|
-
|
174
|
-
|
171
|
+
if table_info := ForeignKey.MAPPED.get(cls.__table_name__, None):
|
172
|
+
table_info.table_object = cls
|
173
|
+
else:
|
174
|
+
ForeignKey.MAPPED[cls.__table_name__] = TableInfo()
|
175
|
+
ForeignKey.MAPPED[cls.__table_name__].table_object = cls
|
176
|
+
|
175
177
|
return None
|
176
178
|
|
177
179
|
|
@@ -285,24 +287,39 @@ class Table(metaclass=TableMeta):
|
|
285
287
|
|
286
288
|
@classmethod
|
287
289
|
def find_dependent_tables(cls) -> tuple["Table", ...]:
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
290
|
+
# TODOL: Dive into new way to return dependent tables
|
291
|
+
def get_involved_tables(graph: dict[Table, list[Table]], table_name: str) -> None:
|
292
|
+
"""
|
293
|
+
Create a graph to be ordered
|
294
|
+
"""
|
295
|
+
table = ForeignKey[Table, Table].MAPPED[table_name]
|
296
|
+
for x in table.referenced_tables:
|
297
|
+
if data := ForeignKey.MAPPED.get(x, None):
|
298
|
+
get_involved_tables(graph, data.table_object.__table_name__)
|
299
|
+
|
300
|
+
graph[table.table_object.__table_name__] = list(table.referenced_tables)
|
301
|
+
return None
|
302
|
+
|
303
|
+
graph: dict[Table, list[Table]] = {}
|
304
|
+
dependent = ForeignKey.MAPPED.get(cls.__table_name__, None)
|
305
|
+
if dependent is None:
|
306
|
+
return tuple([])
|
307
|
+
|
308
|
+
graph[cls.__table_name__] = list(dependent.referenced_tables)
|
309
|
+
get_involved_tables(graph, cls.__table_name__)
|
298
310
|
|
299
311
|
dfs = DFSTraversal.sort(graph)
|
300
|
-
return dfs[: dfs.index(cls)]
|
301
312
|
|
302
|
-
|
303
|
-
|
313
|
+
order_table = dfs[: dfs.index(cls.__table_name__)]
|
314
|
+
|
315
|
+
return [ForeignKey.MAPPED[x].table_object for x in order_table]
|
304
316
|
|
305
317
|
def __eq__(self, __value: Any) -> bool:
|
306
318
|
if isinstance(__value, Table):
|
307
|
-
return
|
319
|
+
return all(
|
320
|
+
(
|
321
|
+
self.__table_name__ == __value.__table_name__,
|
322
|
+
tuple(self.to_dict().items()),
|
323
|
+
)
|
324
|
+
)
|
308
325
|
return False
|
@@ -1,14 +1,14 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ormlambda
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.1.3
|
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
11
|
Requires-Dist: mysql-connector (>=2.2.9,<3.0.0)
|
11
|
-
Requires-Dist: ruff (>=0.4.5,<0.5.0)
|
12
12
|
Description-Content-Type: text/markdown
|
13
13
|
|
14
14
|
# ormMySQL
|
@@ -19,7 +19,7 @@ This ORM is designed to connect with a MySQL server, facilitating the management
|
|
19
19
|
## Initialize MySQLRepository
|
20
20
|
```python
|
21
21
|
from decouple import config
|
22
|
-
from
|
22
|
+
from ormlambda.databases.my_sql import MySQLRepository
|
23
23
|
|
24
24
|
USERNAME = config("USERNAME")
|
25
25
|
PASSWORD = config("PASSWORD")
|
@@ -31,7 +31,7 @@ database = MySQLRepository(user=USERNAME, password=PASSWORD, database="sakila",
|
|
31
31
|
|
32
32
|
## Select all columns
|
33
33
|
```python
|
34
|
-
from
|
34
|
+
from models.address import AddressModel
|
35
35
|
|
36
36
|
result = AddressModel(database).select()
|
37
37
|
```
|
@@ -41,8 +41,8 @@ The `result` var will be of type `tuple[Address, ...]`
|
|
41
41
|
Once the `AddressModel` class is created, we will not only be able to access all the information in that table, but also all the information in all the tables that have foreign keys related to it."
|
42
42
|
|
43
43
|
```python
|
44
|
-
from
|
45
|
-
from
|
44
|
+
from ormlambda import ConditionType
|
45
|
+
from models.address import AddressModel
|
46
46
|
|
47
47
|
|
48
48
|
result = AddressModel(database).where(lambda x: (x.City.Country, ConditionType.REGEXP, r"^[aA]")).select(
|
@@ -135,13 +135,13 @@ The easiest way to map your tables is:
|
|
135
135
|
```python
|
136
136
|
from datetime import datetime
|
137
137
|
|
138
|
-
from
|
138
|
+
from ormlambda import (
|
139
139
|
Column,
|
140
140
|
Table,
|
141
141
|
BaseModel,
|
142
142
|
ForeignKey,
|
143
143
|
)
|
144
|
-
from
|
144
|
+
from ormlambda.common.interfaces import IStatements_two_generic, IRepositoryBase
|
145
145
|
|
146
146
|
|
147
147
|
class Country(Table):
|
@@ -0,0 +1,71 @@
|
|
1
|
+
ormlambda/__init__.py,sha256=eAkyO2ZnXFDZfquCiSGmh_kblT-WapEDd4ZnnfS0fOo,465
|
2
|
+
ormlambda/common/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
3
|
+
ormlambda/common/abstract_classes/__init__.py,sha256=tk2J4Mn_nD-1ZjtMVBE5FH7KR_8ppN_1Kx1s6c38GjM,167
|
4
|
+
ormlambda/common/abstract_classes/abstract_model.py,sha256=5qWXDpgryGuyta0Bv-_W0_KnXtgQE7rVo5HWeFfRz9U,13511
|
5
|
+
ormlambda/common/abstract_classes/non_query_base.py,sha256=5jhvyT7OZaJxlGp9XMP3vQ4ei5QQZBn-fFtJnD640mE,980
|
6
|
+
ormlambda/common/abstract_classes/query_base.py,sha256=6qUFPwsVx45kUW3b66pHiSyjhcH4mzbdkddlGeUnG7c,266
|
7
|
+
ormlambda/common/enums/__init__.py,sha256=4lVKCHi1JalwgNzjsAXqX-C54NJEH83y2v5baMO8fN4,103
|
8
|
+
ormlambda/common/enums/condition_types.py,sha256=mDPMrtzZu4IYv3-q5Zw4NNgwUoNAx4lih5SIDFRn1Qo,309
|
9
|
+
ormlambda/common/enums/join_type.py,sha256=7LEhE34bzYOwJxe8yxPJo_EjQpGylgClAPX1Wt3z4n4,292
|
10
|
+
ormlambda/common/interfaces/INonQueryCommand.py,sha256=7CjLW4sKqkR5zUIGvhRXOtzTs6vypJW1a9EJHlgCw2c,260
|
11
|
+
ormlambda/common/interfaces/IQueryCommand.py,sha256=hfzCosK4-n8RJIb2PYs8b0qU3TNmfYluZXBf47KxxKs,331
|
12
|
+
ormlambda/common/interfaces/IRepositoryBase.py,sha256=I05nCEFMoSRklnQt4fn8ase6YqNeS-qSxRPH_wqrB58,1859
|
13
|
+
ormlambda/common/interfaces/IStatements.py,sha256=h0qgSiWz5rxd9K2FMJPUJau8IKO-ycvQxOSyd74oMq8,9315
|
14
|
+
ormlambda/common/interfaces/__init__.py,sha256=4tthR8pNIHGvgu0n7i3ZEQYP_R3wmqh40l34cAZbM2o,244
|
15
|
+
ormlambda/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
+
ormlambda/components/delete/IDelete.py,sha256=06ZEdbKBxsHSwsGMBu0E1om4WJjojZAm-L3b95eQrcc,139
|
17
|
+
ormlambda/components/delete/__init__.py,sha256=X_at2L4QkxDVK1olXhFHqNemkB8Dxbb7BYqv0EJyu7M,102
|
18
|
+
ormlambda/components/delete/abstract_delete.py,sha256=ca-AO3nM9MMhy0hofNLjnCod92meiWzRT2vitj8N-l4,535
|
19
|
+
ormlambda/components/insert/IInsert.py,sha256=YIfMPlKu7UGgnVpZuhpr0Mtnefe-O85hqk8-GZrVK7w,139
|
20
|
+
ormlambda/components/insert/__init__.py,sha256=TGShCJZwejK3zZCRistBAKoDy2NNDRR_w1LXIbN66Dk,102
|
21
|
+
ormlambda/components/insert/abstract_insert.py,sha256=ctaXd6TB8fo3Fl7NHNA-wOmbCpivU-9uUs7O628RUW0,684
|
22
|
+
ormlambda/components/select/ISelect.py,sha256=_BkOHbO_ICHDjkzgxbenrauCKIDJ40zeFTIG0FjWRCE,319
|
23
|
+
ormlambda/components/select/__init__.py,sha256=BygaFGphVgGT0Zke4WhzdBQMUxevC34Qseok9qutaJE,95
|
24
|
+
ormlambda/components/select/table_column.py,sha256=AF4mQvHJnXzE95yP4iNnZCsNDLaYElL16tIo0ZMs7yc,1311
|
25
|
+
ormlambda/components/update/IUpdate.py,sha256=U-3Wx8lyCglhxf9gCXWO3MVgydG6gfRpzp00_MHC5cU,168
|
26
|
+
ormlambda/components/update/__init__.py,sha256=o1VjlfXgjftZgp64O10rzCGaDZCbdTZRRtjIlojTUWA,102
|
27
|
+
ormlambda/components/update/abstract_update.py,sha256=PV6B7FF9nzixmhnZZGG3Xrot8-ycH-oS3IHkHQdabx4,888
|
28
|
+
ormlambda/components/upsert/IUpsert.py,sha256=2m6Bcwa0X80IDLnf0QErqr01uYEydOnRta9_T1nxjK4,139
|
29
|
+
ormlambda/components/upsert/__init__.py,sha256=2hv7-McdU8Jv1ZJ4J3v94brN2H_fXvVDS8ZEA9CsfPA,102
|
30
|
+
ormlambda/components/upsert/abstract_upsert.py,sha256=ES-AicvMYBoLvH77JR6wir4kPkI4ZF9LA1-eQhsjKYI,684
|
31
|
+
ormlambda/components/where/__init__.py,sha256=mI-ylB6cTTVf3rtCX54apgZrMP6y9tTD7-X3Ct0RFxw,56
|
32
|
+
ormlambda/components/where/abstract_where.py,sha256=93tIJBC81OUUVV6il7mISibBwqJeodQdFFQ9DShDKOQ,344
|
33
|
+
ormlambda/databases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
|
+
ormlambda/databases/my_sql/__init__.py,sha256=3PbOp4WqxJzFOSRwBozqyNtQi25cLLdiJFPDzEnSI70,115
|
35
|
+
ormlambda/databases/my_sql/clauses/__init__.py,sha256=xZ4esQfSRHb68M2Bm2B8deJCtDVrUHgpktFAJnakc8s,694
|
36
|
+
ormlambda/databases/my_sql/clauses/count.py,sha256=vCQR0jK15t7C31lN0tCwZsmYhqx7fKV8xkSJkStO9vE,1151
|
37
|
+
ormlambda/databases/my_sql/clauses/create_database.py,sha256=WnWaAuhxeE71NZKXW37WZ-msRqjum7TFCSRK1IGdSTE,1279
|
38
|
+
ormlambda/databases/my_sql/clauses/delete.py,sha256=nUKNQgwF5YUfzk2icWpecYjrGk5DeXpp7eiwtWCf_3c,1924
|
39
|
+
ormlambda/databases/my_sql/clauses/drop_database.py,sha256=nMM0YUbcH0D9X3bU70Uc6S_dsIrAZy-IrYuIKrQZNrg,505
|
40
|
+
ormlambda/databases/my_sql/clauses/drop_table.py,sha256=meX4e-pVPQ7UwlPSHV5e9HHRblI1BlkLSc7ssl8WUiI,592
|
41
|
+
ormlambda/databases/my_sql/clauses/insert.py,sha256=LO9H8VVK3j62dICXqpEUXKxOHPxkD1LGvogmDq2zmho,2805
|
42
|
+
ormlambda/databases/my_sql/clauses/joins.py,sha256=U6JnUvQo7AXyEeK-X1jMvckXefgAB7ugSmJCZhH1XQI,3058
|
43
|
+
ormlambda/databases/my_sql/clauses/limit.py,sha256=a4lI8FVRKpfXwBQTXdkbVtlQkmzcjE20ymiCy1IaSc4,391
|
44
|
+
ormlambda/databases/my_sql/clauses/offset.py,sha256=81170JhsQndjKlDfQj1ll-tiYHQbW8SuU4IE3mhQF7Y,395
|
45
|
+
ormlambda/databases/my_sql/clauses/order.py,sha256=AcTD7aeaaz-isyjs1_CkRCb7z8b7o5GhpMxc_2G5IgI,1030
|
46
|
+
ormlambda/databases/my_sql/clauses/select.py,sha256=fUeyh2FKud1FOWUGrZCiX-Q2YAcC_EOJ8xCG-SMBDgk,6620
|
47
|
+
ormlambda/databases/my_sql/clauses/update.py,sha256=3Htw0_PT3EckEiF214-V2r63lcNoRBroKZI9yg48Ddg,1867
|
48
|
+
ormlambda/databases/my_sql/clauses/upsert.py,sha256=eW2pQ4ax-GKuXiaWKoSRSS1GrHuILJBsmj83ADbBQ34,1951
|
49
|
+
ormlambda/databases/my_sql/clauses/where_condition.py,sha256=eG514q4Boc2HCZl9MlI5vBKhwQHS9ANpHcTFgLw85vw,8314
|
50
|
+
ormlambda/databases/my_sql/repository.py,sha256=2fgejhGcI48XfUMpTAJrT-PPnNHTaaEiOW8Y5wRv3yc,7191
|
51
|
+
ormlambda/databases/my_sql/statements.py,sha256=1umK_89JWIfViz1cHfTwqIOvMkYZT2IijDiNRmbUvJ4,2300
|
52
|
+
ormlambda/model_base.py,sha256=jH3MTAsVF3V2jXvtKCtpAC-Q102UfBPZ0YiM0nqp-6M,1053
|
53
|
+
ormlambda/utils/__init__.py,sha256=ywMdWqmA2jHj19-W-S04yfaYF5hv4IZ1lZDq0B8Jnjs,142
|
54
|
+
ormlambda/utils/column.py,sha256=5FAGzCU4yvNS4MhwJJ5i73h7RvHD5UCVox0NdzMsMiE,1945
|
55
|
+
ormlambda/utils/dtypes.py,sha256=lzbSYMSKqDhPIEXksxhphxjzd_-sGmwS5dsJhhprn28,7664
|
56
|
+
ormlambda/utils/foreign_key.py,sha256=ewGLPtf1MrFogvwGm_jsSnOLAH2G9virXvLcc3co36I,2973
|
57
|
+
ormlambda/utils/lambda_disassembler/__init__.py,sha256=q23_F2Vp1_XgVpQSbWQPM5wxzRCZOr7ZMb9X5VG_YxU,229
|
58
|
+
ormlambda/utils/lambda_disassembler/dis_types.py,sha256=Myuo9-KSBIJSyr9jfLSDDe1jbrzyOqZNLufv6ODHm98,4824
|
59
|
+
ormlambda/utils/lambda_disassembler/disassembler.py,sha256=Zc_hFeEheCiBtFIo39F573uU3jkkB-VyA-wJGICqs44,2019
|
60
|
+
ormlambda/utils/lambda_disassembler/dtypes.py,sha256=QtftGMCcb4arAQnXkwGQ1VeV-6x0mZdRTfZmxLkAtFo,6449
|
61
|
+
ormlambda/utils/lambda_disassembler/name_of.py,sha256=Cjic_GzqgArxx7kDUMOGYmmNRHj7HcxG-kcDfAhA5yk,1142
|
62
|
+
ormlambda/utils/lambda_disassembler/nested_element.py,sha256=nXwytOwBbPYSTMxksQTRMhSeqRIMpIcVWg70loVtQ_k,1234
|
63
|
+
ormlambda/utils/lambda_disassembler/tree_instruction.py,sha256=QUnhG89WKJyAlEWAjK5SRZwYgFheHnMw-yUjvVvYhvM,5122
|
64
|
+
ormlambda/utils/module_tree/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
65
|
+
ormlambda/utils/module_tree/dfs_traversal.py,sha256=lSF03G63XtJFLp03ueAmsHMBvhUkjptDbK3IugXm8iU,1425
|
66
|
+
ormlambda/utils/module_tree/dynamic_module.py,sha256=zwvjU3U2cz6H2CDp9Gncs5D5bSAyfITNa2SDqFDl8rw,8551
|
67
|
+
ormlambda/utils/table_constructor.py,sha256=I2oFTfa6BPTILY6UDYGZy4fJxZazZMkH89NObkfRemo,11480
|
68
|
+
ormlambda-1.1.3.dist-info/LICENSE,sha256=xBprFw8GJLdHMOoUqDk0427EvjIcbEREvXXVFULuuXU,1080
|
69
|
+
ormlambda-1.1.3.dist-info/METADATA,sha256=ATf86A84P6lj2QvkIzO91QLo5jzgAHyax0ZaI2-AqC8,8219
|
70
|
+
ormlambda-1.1.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
71
|
+
ormlambda-1.1.3.dist-info/RECORD,,
|