ormlambda 1.0.1__py3-none-any.whl → 1.2.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 (54) hide show
  1. ormlambda/__init__.py +8 -2
  2. ormlambda/common/__init__.py +0 -1
  3. ormlambda/common/abstract_classes/__init__.py +1 -1
  4. ormlambda/common/abstract_classes/abstract_model.py +30 -13
  5. ormlambda/common/abstract_classes/non_query_base.py +7 -5
  6. ormlambda/common/abstract_classes/query_base.py +5 -2
  7. ormlambda/common/enums/__init__.py +1 -1
  8. ormlambda/common/enums/join_type.py +2 -1
  9. ormlambda/common/interfaces/IQueryCommand.py +2 -1
  10. ormlambda/common/interfaces/IRepositoryBase.py +4 -0
  11. ormlambda/common/interfaces/IStatements.py +25 -14
  12. ormlambda/common/interfaces/__init__.py +1 -1
  13. ormlambda/components/delete/abstract_delete.py +6 -3
  14. ormlambda/components/insert/IInsert.py +1 -1
  15. ormlambda/components/insert/abstract_insert.py +8 -4
  16. ormlambda/components/select/ISelect.py +1 -1
  17. ormlambda/components/select/table_column.py +5 -1
  18. ormlambda/components/update/IUpdate.py +1 -1
  19. ormlambda/components/update/__init__.py +1 -1
  20. ormlambda/components/update/abstract_update.py +9 -5
  21. ormlambda/components/upsert/__init__.py +1 -1
  22. ormlambda/components/upsert/abstract_upsert.py +8 -4
  23. ormlambda/components/where/abstract_where.py +6 -2
  24. ormlambda/databases/my_sql/clauses/__init__.py +1 -0
  25. ormlambda/databases/my_sql/clauses/count.py +35 -0
  26. ormlambda/databases/my_sql/clauses/create_database.py +17 -10
  27. ormlambda/databases/my_sql/clauses/delete.py +7 -4
  28. ormlambda/databases/my_sql/clauses/drop_database.py +1 -1
  29. ormlambda/databases/my_sql/clauses/drop_table.py +1 -1
  30. ormlambda/databases/my_sql/clauses/insert.py +4 -3
  31. ormlambda/databases/my_sql/clauses/joins.py +8 -7
  32. ormlambda/databases/my_sql/clauses/limit.py +1 -1
  33. ormlambda/databases/my_sql/clauses/offset.py +1 -1
  34. ormlambda/databases/my_sql/clauses/order.py +3 -3
  35. ormlambda/databases/my_sql/clauses/select.py +5 -5
  36. ormlambda/databases/my_sql/clauses/update.py +3 -3
  37. ormlambda/databases/my_sql/clauses/upsert.py +3 -3
  38. ormlambda/databases/my_sql/clauses/where_condition.py +5 -5
  39. ormlambda/databases/my_sql/repository.py +26 -4
  40. ormlambda/databases/my_sql/statements.py +14 -5
  41. ormlambda/model_base.py +0 -2
  42. ormlambda/utils/column.py +4 -3
  43. ormlambda/utils/dtypes.py +6 -8
  44. ormlambda/utils/foreign_key.py +55 -10
  45. ormlambda/utils/lambda_disassembler/__init__.py +1 -1
  46. ormlambda/utils/lambda_disassembler/dis_types.py +22 -25
  47. ormlambda/utils/lambda_disassembler/tree_instruction.py +1 -1
  48. ormlambda/utils/module_tree/dynamic_module.py +6 -4
  49. ormlambda/utils/table_constructor.py +39 -22
  50. {ormlambda-1.0.1.dist-info → ormlambda-1.2.0.dist-info}/METADATA +13 -9
  51. ormlambda-1.2.0.dist-info/RECORD +71 -0
  52. ormlambda-1.0.1.dist-info/RECORD +0 -70
  53. {ormlambda-1.0.1.dist-info → ormlambda-1.2.0.dist-info}/LICENSE +0 -0
  54. {ormlambda-1.0.1.dist-info → ormlambda-1.2.0.dist-info}/WHEEL +0 -0
@@ -1,8 +1,8 @@
1
1
  from typing import override, Any
2
2
 
3
- from ....utils import Table
4
- from ....components.upsert import UpsertQueryBase
5
- from ....common.interfaces import IRepositoryBase
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 ....common.enums import ConditionType
5
- from ....utils.lambda_disassembler.tree_instruction import TreeInstruction, TupleInstruction
6
- from ....common.interfaces.IQueryCommand import IQuery
7
- from ....components.where.abstract_where import AbstractWhere
8
- from ....utils import Table
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 ...common.interfaces import IRepositoryBase
11
- from ...utils.module_tree.dynamic_module import ModuleTree
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] = {dict: _dict, tuple: _tuple}
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 typing import override, Type
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 ...common.abstract_classes import AbstractSQLStatements
5
- from ...utils import Table
6
- from ...common.interfaces import IQuery, IRepositoryBase
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
@@ -1,4 +1,3 @@
1
- # region imports
2
1
  from typing import Type
3
2
 
4
3
 
@@ -8,7 +7,6 @@ from .common.abstract_classes import AbstractSQLStatements
8
7
  from .databases.my_sql import MySQLStatements, MySQLRepository
9
8
 
10
9
 
11
-
12
10
  # endregion
13
11
 
14
12
 
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, # must be the same variable name as the instance variable name in Table's __init__ class
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,10 +61,6 @@ 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:
@@ -77,15 +73,17 @@ def transform_py_dtype_into_query_dtype(dtype: Any) -> str:
77
73
  datetime.datetime: "DATETIME",
78
74
  datetime.date: "DATE",
79
75
  bytes: "BLOB",
76
+ bytearray: "BLOB",
80
77
  str: "VARCHAR(255)",
81
- np.uint64: "BIGINT UNSIGNED"
78
+ np.uint64: "BIGINT UNSIGNED",
82
79
  }
83
80
 
81
+ res = dicc.get(dtype, None)
82
+ if res is None:
83
+ raise ValueError(f"datatype '{dtype}' is not expected.")
84
84
  return dicc[dtype]
85
85
 
86
86
 
87
-
88
-
89
87
  # 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
88
  def get_query_clausule(column_obj: Column) -> str:
91
89
  dtype: str = transform_py_dtype_into_query_dtype(column_obj.dtype)
@@ -1,13 +1,51 @@
1
- from collections import defaultdict
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 ForeignKey[Tbl1:Table, Tbl2:Table]:
10
- MAPPED: dict[Tbl1, dict[Tbl2, Callable[[Tbl1, Tbl2], bool]]] = defaultdict(dict)
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: "Table", relationship: Callable[[Tbl1, Tbl2], bool]) -> None:
24
- cls.MAPPED[orig_table][referenced_table] = relationship
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: "Table") -> list[str]:
71
+ def create_query(cls, orig_table: Table) -> list[str]:
29
72
  clauses: list[str] = []
30
- for referenced_table, _lambda in ForeignKey[Tbl1, Tbl2].MAPPED[orig_table].items():
31
- dissambler: Disassembler = Disassembler(_lambda)
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 {referenced_table.__table_name__}({referenced_col})")
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= 'FOR_ITER'
116
- JUMP_FORWARD= 'JUMP_FORWARD'
117
- POP_JUMP_IF_FALSE= 'POP_JUMP_IF_FALSE'
118
- POP_JUMP_IF_TRUE= 'POP_JUMP_IF_TRUE'
119
- SEND= 'SEND'
120
- POP_JUMP_IF_NOT_NONE= 'POP_JUMP_IF_NOT_NONE'
121
- POP_JUMP_IF_NONE= 'POP_JUMP_IF_NONE'
122
- JUMP_BACKWARD_NO_INTERRUPT= 'JUMP_BACKWARD_NO_INTERRUPT'
123
- JUMP_BACKWARD= 'JUMP_BACKWARD'
124
- STORE_NAME= 'STORE_NAME'
125
- DELETE_NAME= 'DELETE_NAME'
126
- STORE_ATTR= 'STORE_ATTR'
127
- DELETE_ATTR= 'DELETE_ATTR'
128
- STORE_GLOBAL= 'STORE_GLOBAL'
129
- DELETE_GLOBAL= 'DELETE_GLOBAL'
130
- LOAD_NAME= 'LOAD_NAME'
131
- LOAD_ATTR= 'LOAD_ATTR'
132
- IMPORT_NAME= 'IMPORT_NAME'
133
- IMPORT_FROM= 'IMPORT_FROM'
134
- LOAD_GLOBAL= 'LOAD_GLOBAL'
135
- LOAD_SUPER_ATTR= 'LOAD_SUPER_ATTR'
136
- LOAD_FROM_DICT_OR_GLOBALS= '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 ...common.enums.condition_types import ConditionType
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 ..table_constructor import Table
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[Type[Table], list[Type[Table]]] = defaultdict(list)
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.__add_fk_if_exists__(cls_object)
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 __add_fk_if_exists__(cls: "Table") -> None:
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, when instantiating the object, we replace the table name with the class itself.
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 data := ForeignKey.MAPPED.get(cls.__table_name__):
173
- ForeignKey.MAPPED[cls] = data
174
- del ForeignKey.MAPPED[cls.__table_name__]
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
- def get_involved_tables(graph: dict[Table, list[Table]], table: Table) -> None:
289
- for tbl in ForeignKey[Table, Table].MAPPED[table].keys():
290
- if ForeignKey.MAPPED[tbl]:
291
- get_involved_tables(graph, tbl)
292
- graph[tbl] = list(ForeignKey.MAPPED[tbl].keys())
293
- return None
294
-
295
- graph: dict[Table, list[Table]] = defaultdict(list)
296
- graph[cls] = list(ForeignKey.MAPPED[cls].keys())
297
- get_involved_tables(graph, cls)
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
- def __hash__(self) -> int:
303
- return hash(self.to_dict().values())
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 hash(self) == hash(__value)
319
+ return all(
320
+ (
321
+ self.__table_name__ == __value.__table_name__,
322
+ tuple(self.to_dict().items()),
323
+ )
324
+ )
308
325
  return False
@@ -1,16 +1,20 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ormlambda
3
- Version: 1.0.1
3
+ Version: 1.2.0
4
4
  Summary: ORM designed to interact with the database (currently with MySQL) using lambda functions and nested functions
5
5
  Author: p-hzamora
6
6
  Author-email: p.hzamora@icloud.com
7
7
  Requires-Python: >=3.12,<4.0
8
8
  Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.12
10
- Requires-Dist: mysql-connector (>=2.2.9,<3.0.0)
11
- Requires-Dist: ruff (>=0.4.5,<0.5.0)
10
+ Requires-Dist: fluent-validation (>=3.1.0,<4.0.0)
11
+ Requires-Dist: mysql-connector-python (>=2.2.9,<3.0.0)
12
12
  Description-Content-Type: text/markdown
13
13
 
14
+ ![PyPI version](https://img.shields.io/pypi/v/ormlambda.svg)
15
+ ![downloads](https://img.shields.io/pypi/dm/ormlambda?label=downloads)
16
+ ![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)
17
+
14
18
  # ormMySQL
15
19
  This ORM is designed to connect with a MySQL server, facilitating the management of various database queries. Built with flexibility and efficiency in mind, this ORM empowers developers to interact with the database using lambda functions, allowing for concise and expressive query construction.
16
20
 
@@ -19,7 +23,7 @@ This ORM is designed to connect with a MySQL server, facilitating the management
19
23
  ## Initialize MySQLRepository
20
24
  ```python
21
25
  from decouple import config
22
- from src.ormmysql.databases.my_sql import MySQLRepository
26
+ from ormlambda.databases.my_sql import MySQLRepository
23
27
 
24
28
  USERNAME = config("USERNAME")
25
29
  PASSWORD = config("PASSWORD")
@@ -31,7 +35,7 @@ database = MySQLRepository(user=USERNAME, password=PASSWORD, database="sakila",
31
35
 
32
36
  ## Select all columns
33
37
  ```python
34
- from src.test.models.address import AddressModel
38
+ from models.address import AddressModel
35
39
 
36
40
  result = AddressModel(database).select()
37
41
  ```
@@ -41,8 +45,8 @@ The `result` var will be of type `tuple[Address, ...]`
41
45
  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
46
 
43
47
  ```python
44
- from src.ormmysql.common.enums import ConditionType
45
- from src.test.models.address import AddressModel
48
+ from ormlambda import ConditionType
49
+ from models.address import AddressModel
46
50
 
47
51
 
48
52
  result = AddressModel(database).where(lambda x: (x.City.Country, ConditionType.REGEXP, r"^[aA]")).select(
@@ -135,13 +139,13 @@ The easiest way to map your tables is:
135
139
  ```python
136
140
  from datetime import datetime
137
141
 
138
- from src.ormmysql import (
142
+ from ormlambda import (
139
143
  Column,
140
144
  Table,
141
145
  BaseModel,
142
146
  ForeignKey,
143
147
  )
144
- from src.ormmysql.common.interfaces import IStatements_two_generic, IRepositoryBase
148
+ from ormlambda.common.interfaces import IStatements_two_generic, IRepositoryBase
145
149
 
146
150
 
147
151
  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=ABdecwq4G_Gg4wvjpj7LWDntdjRmcMMLWOuG2pfAqfg,1939
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=1kRsT5JggNS1DMWgSUdBb67CefQHnZ-VTN1WI7nN2yQ,7879
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.2.0.dist-info/LICENSE,sha256=xBprFw8GJLdHMOoUqDk0427EvjIcbEREvXXVFULuuXU,1080
69
+ ormlambda-1.2.0.dist-info/METADATA,sha256=5uv_JdYZ2gWIL-P4HohMxMvw96jLizPd2aZi77MWGyQ,8427
70
+ ormlambda-1.2.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
71
+ ormlambda-1.2.0.dist-info/RECORD,,