ormlambda 2.11.2__py3-none-any.whl → 3.7.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 (119) hide show
  1. ormlambda/__init__.py +11 -9
  2. ormlambda/caster/__init__.py +3 -0
  3. ormlambda/caster/base_caster.py +69 -0
  4. ormlambda/caster/caster.py +48 -0
  5. ormlambda/caster/interfaces/ICaster.py +26 -0
  6. ormlambda/caster/interfaces/__init__.py +1 -0
  7. ormlambda/common/__init__.py +1 -1
  8. ormlambda/common/abstract_classes/__init__.py +3 -3
  9. ormlambda/common/abstract_classes/decomposition_query.py +117 -319
  10. ormlambda/common/abstract_classes/non_query_base.py +1 -1
  11. ormlambda/common/enums/condition_types.py +2 -1
  12. ormlambda/common/enums/join_type.py +4 -1
  13. ormlambda/common/errors/__init__.py +15 -2
  14. ormlambda/common/global_checker.py +28 -0
  15. ormlambda/common/interfaces/ICustomAlias.py +4 -1
  16. ormlambda/common/interfaces/IDecompositionQuery.py +9 -34
  17. ormlambda/common/interfaces/IJoinSelector.py +21 -0
  18. ormlambda/common/interfaces/__init__.py +4 -6
  19. ormlambda/components/__init__.py +4 -0
  20. ormlambda/components/insert/abstract_insert.py +1 -1
  21. ormlambda/components/select/ISelect.py +17 -0
  22. ormlambda/components/select/__init__.py +1 -0
  23. ormlambda/components/update/abstract_update.py +4 -4
  24. ormlambda/components/upsert/abstract_upsert.py +1 -1
  25. ormlambda/databases/__init__.py +5 -0
  26. ormlambda/databases/my_sql/__init__.py +3 -1
  27. ormlambda/databases/my_sql/caster/__init__.py +1 -0
  28. ormlambda/databases/my_sql/caster/caster.py +38 -0
  29. ormlambda/databases/my_sql/caster/read.py +39 -0
  30. ormlambda/databases/my_sql/caster/types/__init__.py +8 -0
  31. ormlambda/databases/my_sql/caster/types/bytes.py +31 -0
  32. ormlambda/databases/my_sql/caster/types/datetime.py +34 -0
  33. ormlambda/databases/my_sql/caster/types/float.py +31 -0
  34. ormlambda/databases/my_sql/caster/types/int.py +31 -0
  35. ormlambda/databases/my_sql/caster/types/iterable.py +31 -0
  36. ormlambda/databases/my_sql/caster/types/none.py +30 -0
  37. ormlambda/databases/my_sql/caster/types/point.py +43 -0
  38. ormlambda/databases/my_sql/caster/types/string.py +31 -0
  39. ormlambda/databases/my_sql/caster/write.py +37 -0
  40. ormlambda/databases/my_sql/clauses/ST_AsText.py +36 -0
  41. ormlambda/databases/my_sql/clauses/ST_Contains.py +31 -0
  42. ormlambda/databases/my_sql/clauses/__init__.py +6 -4
  43. ormlambda/databases/my_sql/clauses/alias.py +24 -21
  44. ormlambda/databases/my_sql/clauses/count.py +32 -28
  45. ormlambda/databases/my_sql/clauses/create_database.py +3 -4
  46. ormlambda/databases/my_sql/clauses/delete.py +10 -10
  47. ormlambda/databases/my_sql/clauses/drop_database.py +3 -5
  48. ormlambda/databases/my_sql/clauses/drop_table.py +3 -3
  49. ormlambda/databases/my_sql/clauses/group_by.py +4 -7
  50. ormlambda/databases/my_sql/clauses/insert.py +33 -19
  51. ormlambda/databases/my_sql/clauses/joins.py +66 -59
  52. ormlambda/databases/my_sql/clauses/limit.py +1 -1
  53. ormlambda/databases/my_sql/clauses/offset.py +1 -1
  54. ormlambda/databases/my_sql/clauses/order.py +36 -23
  55. ormlambda/databases/my_sql/clauses/select.py +25 -36
  56. ormlambda/databases/my_sql/clauses/update.py +38 -13
  57. ormlambda/databases/my_sql/clauses/upsert.py +2 -2
  58. ormlambda/databases/my_sql/clauses/where.py +45 -0
  59. ormlambda/databases/my_sql/functions/concat.py +24 -27
  60. ormlambda/databases/my_sql/functions/max.py +32 -28
  61. ormlambda/databases/my_sql/functions/min.py +32 -28
  62. ormlambda/databases/my_sql/functions/sum.py +32 -28
  63. ormlambda/databases/my_sql/join_context.py +75 -0
  64. ormlambda/databases/my_sql/repository/__init__.py +1 -0
  65. ormlambda/databases/my_sql/{repository.py → repository/repository.py} +104 -73
  66. ormlambda/databases/my_sql/statements.py +231 -153
  67. ormlambda/engine/__init__.py +0 -0
  68. ormlambda/engine/template.py +47 -0
  69. ormlambda/model/__init__.py +0 -0
  70. ormlambda/model/base_model.py +37 -0
  71. ormlambda/repository/__init__.py +2 -0
  72. ormlambda/repository/base_repository.py +14 -0
  73. ormlambda/repository/interfaces/IDatabaseConnection.py +12 -0
  74. ormlambda/{common → repository}/interfaces/IRepositoryBase.py +6 -5
  75. ormlambda/repository/interfaces/__init__.py +2 -0
  76. ormlambda/sql/__init__.py +3 -0
  77. ormlambda/sql/clause_info/__init__.py +3 -0
  78. ormlambda/sql/clause_info/clause_info.py +434 -0
  79. ormlambda/sql/clause_info/clause_info_context.py +87 -0
  80. ormlambda/sql/clause_info/interface/IAggregate.py +10 -0
  81. ormlambda/sql/clause_info/interface/__init__.py +1 -0
  82. ormlambda/sql/column.py +126 -0
  83. ormlambda/sql/comparer.py +156 -0
  84. ormlambda/sql/foreign_key.py +115 -0
  85. ormlambda/sql/interfaces/__init__.py +0 -0
  86. ormlambda/sql/table/__init__.py +1 -0
  87. ormlambda/{utils → sql/table}/fields.py +6 -5
  88. ormlambda/{utils → sql/table}/table_constructor.py +43 -91
  89. ormlambda/sql/types.py +25 -0
  90. ormlambda/statements/__init__.py +2 -0
  91. ormlambda/statements/base_statement.py +129 -0
  92. ormlambda/statements/interfaces/IStatements.py +309 -0
  93. ormlambda/statements/interfaces/__init__.py +1 -0
  94. ormlambda/statements/types.py +51 -0
  95. ormlambda/utils/__init__.py +1 -3
  96. ormlambda/utils/module_tree/__init__.py +1 -0
  97. ormlambda/utils/module_tree/dynamic_module.py +20 -14
  98. {ormlambda-2.11.2.dist-info → ormlambda-3.7.0.dist-info}/METADATA +132 -68
  99. ormlambda-3.7.0.dist-info/RECORD +117 -0
  100. ormlambda/common/abstract_classes/abstract_model.py +0 -115
  101. ormlambda/common/interfaces/IAggregate.py +0 -10
  102. ormlambda/common/interfaces/IStatements.py +0 -348
  103. ormlambda/components/where/__init__.py +0 -1
  104. ormlambda/components/where/abstract_where.py +0 -15
  105. ormlambda/databases/my_sql/clauses/where_condition.py +0 -222
  106. ormlambda/model_base.py +0 -36
  107. ormlambda/utils/column.py +0 -105
  108. ormlambda/utils/foreign_key.py +0 -81
  109. ormlambda/utils/lambda_disassembler/__init__.py +0 -4
  110. ormlambda/utils/lambda_disassembler/dis_types.py +0 -133
  111. ormlambda/utils/lambda_disassembler/disassembler.py +0 -69
  112. ormlambda/utils/lambda_disassembler/dtypes.py +0 -103
  113. ormlambda/utils/lambda_disassembler/name_of.py +0 -41
  114. ormlambda/utils/lambda_disassembler/nested_element.py +0 -44
  115. ormlambda/utils/lambda_disassembler/tree_instruction.py +0 -145
  116. ormlambda-2.11.2.dist-info/RECORD +0 -81
  117. /ormlambda/{utils → sql}/dtypes.py +0 -0
  118. {ormlambda-2.11.2.dist-info → ormlambda-3.7.0.dist-info}/LICENSE +0 -0
  119. {ormlambda-2.11.2.dist-info → ormlambda-3.7.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,156 @@
1
+ from __future__ import annotations
2
+ import abc
3
+ import re
4
+ import typing as tp
5
+ from ormlambda.common.interfaces.IQueryCommand import IQuery
6
+
7
+
8
+ from ormlambda.sql.types import ConditionType, ComparerTypes
9
+ from ormlambda.sql.clause_info import ClauseInfo
10
+ from ormlambda import ConditionType as ConditionEnum
11
+
12
+ if tp.TYPE_CHECKING:
13
+ from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
14
+ from ormlambda.sql import Table
15
+
16
+
17
+ class ICleaner(abc.ABC):
18
+ @staticmethod
19
+ @abc.abstractmethod
20
+ def clean(value: str): ...
21
+
22
+
23
+ class IgnoreCase(ICleaner):
24
+ @staticmethod
25
+ def clean(value: str) -> str:
26
+ return value.lower()
27
+
28
+
29
+ DICC_FLAGS = {
30
+ re.IGNORECASE: IgnoreCase,
31
+ }
32
+
33
+
34
+ class CleanValue:
35
+ def __init__(self, name: str, *flags: re.RegexFlag):
36
+ self._flags = flags
37
+ self._filename: str = name
38
+
39
+ def clean(self) -> str:
40
+ temp_name = self._filename
41
+ for flag in self._flags:
42
+ cleaner = DICC_FLAGS.get(flag, None)
43
+ if cleaner:
44
+ temp_name = cleaner.clean(temp_name)
45
+ return temp_name
46
+
47
+
48
+ class Comparer[LTable: Table, LProp, RTable: Table, RProp](IQuery):
49
+ def __init__(
50
+ self,
51
+ left_condition: ConditionType[LProp],
52
+ right_condition: ConditionType[RProp],
53
+ compare: ComparerTypes,
54
+ context: ClauseContextType = None,
55
+ flags: tp.Optional[tp.Iterable[re.RegexFlag]] = None,
56
+ ) -> None:
57
+ self._context: ClauseContextType = context
58
+ self._compare: ComparerTypes = compare
59
+ self._left_condition: Comparer[LTable, LProp, RTable, RProp] | ClauseInfo[LTable] = left_condition
60
+ self._right_condition: Comparer[LTable, LProp, RTable, RProp] | ClauseInfo[RTable] = right_condition
61
+ self._flags = flags
62
+
63
+ def set_context(self, context: ClauseContextType) -> None:
64
+ self._context = context
65
+
66
+ def __repr__(self) -> str:
67
+ return f"{Comparer.__name__}: {self.query}"
68
+
69
+ def _create_clause_info[TTable](self, cond: ConditionType[LProp]) -> Comparer[LTable, LProp, RTable, RProp] | ClauseInfo[TTable]:
70
+ from ormlambda import Column
71
+
72
+ if isinstance(cond, Comparer):
73
+ return cond
74
+ if isinstance(cond, Column):
75
+ return ClauseInfo(cond.table, cond, alias_clause=None, context=self._context)
76
+ # it a value that's not depend of any Table
77
+ return ClauseInfo(None, cond, alias_clause=None, context=self._context)
78
+
79
+ @property
80
+ def left_condition(self) -> Comparer | ClauseInfo[LTable]:
81
+ return self._create_clause_info(self._left_condition)
82
+
83
+ @property
84
+ def right_condition(self) -> Comparer | ClauseInfo[RTable]:
85
+ return self._create_clause_info(self._right_condition)
86
+
87
+ @property
88
+ def compare(self) -> ComparerTypes:
89
+ return self._compare
90
+
91
+ @property
92
+ def query(self) -> str:
93
+ lcond = self.left_condition.query
94
+ rcond = self.right_condition.query
95
+
96
+ if self._flags:
97
+ rcond = CleanValue(rcond, self._flags).clean()
98
+
99
+ return f"{lcond} {self._compare} {rcond}"
100
+
101
+ def __and__(self, other: Comparer, context: ClauseContextType = None) -> Comparer:
102
+ # Customize the behavior of '&'
103
+ return Comparer(self, other, "AND", context=context)
104
+
105
+ def __or__(self, other: Comparer, context: ClauseContextType = None) -> Comparer:
106
+ # Customize the behavior of '|'
107
+ return Comparer(self, other, "OR", context=context)
108
+
109
+ @classmethod
110
+ def join_comparers(cls, comparers: list[Comparer], restrictive: bool = True, context: ClauseContextType = None) -> str:
111
+ if not isinstance(comparers, tp.Iterable):
112
+ raise ValueError(f"Excepted '{Comparer.__name__}' iterable not {type(comparers).__name__}")
113
+ if len(comparers) == 1:
114
+ comparer = comparers[0]
115
+ comparer.set_context(context)
116
+ return comparer.query
117
+
118
+ join_method = cls.__or__ if not restrictive else cls.__and__
119
+
120
+ ini_comparer: Comparer = None
121
+ for i in range(len(comparers) - 1):
122
+ if ini_comparer is None:
123
+ ini_comparer = comparers[i]
124
+ ini_comparer.set_context(context)
125
+ right_comparer = comparers[i + 1]
126
+ right_comparer.set_context(context)
127
+ new_comparer = join_method(ini_comparer, right_comparer, context=context)
128
+ ini_comparer = new_comparer
129
+ return new_comparer.query
130
+
131
+
132
+ class Regex[LProp, RProp](Comparer[None, LProp, None, RProp]):
133
+ def __init__(
134
+ self,
135
+ left_condition: ConditionType[LProp],
136
+ right_condition: ConditionType[RProp],
137
+ context: ClauseContextType = None,
138
+ flags: tp.Optional[tp.Iterable[re.RegexFlag]] = None,
139
+ ):
140
+ super().__init__(
141
+ left_condition=left_condition,
142
+ right_condition=right_condition,
143
+ compare=ConditionEnum.REGEXP.value,
144
+ context=context,
145
+ flags=flags, # Pass as a named parameter instead
146
+ )
147
+
148
+
149
+ class Like[LProp, RProp](Comparer[None, LProp, None, RProp]):
150
+ def __init__(
151
+ self,
152
+ left_condition: ConditionType[LProp],
153
+ right_condition: ConditionType[RProp],
154
+ context: ClauseContextType = None,
155
+ ):
156
+ super().__init__(left_condition, right_condition, ConditionEnum.LIKE.value, context)
@@ -0,0 +1,115 @@
1
+ from __future__ import annotations
2
+ from typing import Callable, TYPE_CHECKING, Optional, Any, Type, overload
3
+
4
+ from ormlambda.common.interfaces.IQueryCommand import IQuery
5
+
6
+
7
+ if TYPE_CHECKING:
8
+ from ormlambda.sql.comparer import Comparer
9
+ from ormlambda import Table
10
+ from ormlambda.sql.clause_info.clause_info_context import ClauseContextType
11
+
12
+
13
+ class ForeignKey[TLeft: Table, TRight: Table](IQuery):
14
+ stored_calls: set[ForeignKey] = set()
15
+
16
+ @overload
17
+ def __new__[LProp, RProp](self, comparer: Comparer[LProp, RProp], clause_name: str) -> None: ...
18
+ @overload
19
+ def __new__[LProp, TRight, RProp](cls, tright: Type[TRight], relationship: Callable[[TLeft, TRight], Any | Comparer[TLeft, LProp, TRight, RProp]]) -> TRight: ...
20
+
21
+ def __new__[LProp, TRight, RProp](cls, tright: Optional[TRight] = None, relationship: Optional[Callable[[TLeft, TRight], Any | Comparer[TLeft, LProp, TRight, RProp]]] = None, *, comparer: Optional[Comparer] = None, clause_name: Optional[str] = None) -> TRight:
22
+ return super().__new__(cls)
23
+
24
+ def __init__[LProp, RProp](
25
+ self,
26
+ tright: Optional[TRight] = None,
27
+ relationship: Optional[Callable[[TLeft, TRight], Any | Comparer[TLeft, LProp, TRight, RProp]]] = None,
28
+ *,
29
+ comparer: Optional[Comparer] = None,
30
+ clause_name: Optional[str] = None,
31
+ ) -> None:
32
+ if comparer is not None and clause_name is not None:
33
+ self.__init__with_comparer(comparer, clause_name)
34
+ else:
35
+ self.__init_with_callable(tright, relationship)
36
+
37
+ def __init__with_comparer[LProp, RProp](self, comparer: Comparer[LProp, RProp], clause_name: str) -> None:
38
+ self._relationship = None
39
+ self._tleft: TLeft = comparer.left_condition.table
40
+ self._tright: TRight = comparer.right_condition.table
41
+ self._clause_name: str = clause_name
42
+ self._comparer: Comparer[LProp, RProp] = comparer
43
+
44
+ def __init_with_callable[LProp, RProp](self, tright: Optional[TRight], relationship: Optional[Callable[[TLeft, TRight], Comparer[LProp, RProp]]]) -> None:
45
+ self._relationship: Callable[[TLeft, TRight], Comparer[LProp, RProp]] = relationship
46
+ self._tleft: TLeft = None
47
+ self._tright: TRight = tright
48
+ self._clause_name: str = None
49
+ self._comparer: Optional[Comparer] = None
50
+
51
+ def __set_name__(self, owner: TLeft, name) -> None:
52
+ self._tleft: TLeft = owner
53
+ self._clause_name: str = name
54
+
55
+ def __get__(self, obj: Optional[TRight], objtype=None) -> ForeignKey[TLeft, TRight] | TRight:
56
+ if not obj:
57
+ ForeignKey.stored_calls.add(self)
58
+ return self
59
+ return self._tright
60
+
61
+ def __set__(self, obj, value):
62
+ raise AttributeError(f"The {ForeignKey.__name__} '{self._clause_name}' in the '{self._tleft.__table_name__}' table cannot be overwritten.")
63
+
64
+ def __getattr__(self, name: str):
65
+ if self._tright is None:
66
+ raise AttributeError("No right table assigned to ForeignKey")
67
+ return getattr(self._tright, name)
68
+
69
+ def __repr__(self) -> str:
70
+ return f"{self.__class__.__name__}(" f"left={self._tleft.__name__ if self._tleft else 'None'}, " f"right={self._tright.__name__ if self._tright else 'None'}, " f"name={self._clause_name})"
71
+
72
+ @property
73
+ def tleft(self) -> TLeft:
74
+ return self._tleft
75
+
76
+ @property
77
+ def tright(self) -> TRight:
78
+ return self._tright
79
+
80
+ @property
81
+ def clause_name(self) -> str:
82
+ return self._clause_name
83
+
84
+ @property
85
+ def query(self) -> str:
86
+ compare = self.resolved_function()
87
+ rcon = alias if (alias := compare.right_condition.alias_table) else compare.right_condition.table.__table_name__
88
+ return f"FOREIGN KEY ({self._tleft.__table_name__}) REFERENCES {rcon}({compare.right_condition._column.column_name})"
89
+
90
+ @property
91
+ def alias(self) -> str:
92
+ self._comparer = self.resolved_function()
93
+ lcol = self._comparer.left_condition._column.column_name
94
+ rcol = self._comparer.right_condition._column.column_name
95
+ return f"{self.tleft.__table_name__}_{lcol}_{rcol}"
96
+
97
+ @classmethod
98
+ def create_query(cls, orig_table: Table) -> list[str]:
99
+ clauses: list[str] = []
100
+
101
+ for attr in vars(orig_table):
102
+ if isinstance(attr, ForeignKey):
103
+ clauses.append(attr.query)
104
+ return clauses
105
+
106
+ def resolved_function[LProp: Any, RProp: Any](self, context: ClauseContextType = None) -> Comparer[LProp, RProp]:
107
+ """ """
108
+ if self._comparer is not None:
109
+ return self._comparer
110
+
111
+ left = self._tleft
112
+ right = self._tright
113
+ comparer = self._relationship(left, right)
114
+ comparer.set_context(context)
115
+ return comparer
File without changes
@@ -0,0 +1 @@
1
+ from .table_constructor import Table, TableMeta # noqa: F401
@@ -1,9 +1,9 @@
1
1
  import typing as tp
2
- from .column import Column
2
+ from ormlambda.sql import Column
3
3
 
4
4
  __all__ = ["get_fields"]
5
5
 
6
- MISSING = lambda: Column() # COMMENT: Very Important to avoid reusing the same variable across different classes. # noqa: E731
6
+ MISSING = lambda x: Column(x) # COMMENT: Very Important to avoid reusing the same variable across different classes. # noqa: E731
7
7
 
8
8
 
9
9
  class Field[TProp: tp.AnnotatedAny]:
@@ -34,7 +34,7 @@ class Field[TProp: tp.AnnotatedAny]:
34
34
 
35
35
  @property
36
36
  def assginment(self) -> str:
37
- return f"self._{self.name} = {self.default.__to_string__(self)}"
37
+ return f"self.{self.name} = {self.default.column_name}"
38
38
 
39
39
 
40
40
  def get_fields[T, TProp](cls: tp.Type[T]) -> tp.Iterable[Field]:
@@ -50,11 +50,12 @@ def get_fields[T, TProp](cls: tp.Type[T]) -> tp.Iterable[Field]:
50
50
  # type_ must by Column object
51
51
  field_type: TProp = type_
52
52
 
53
- default: Column = getattr(cls, name, MISSING())
53
+ default: Column = getattr(cls, name, MISSING(field_type))
54
+ Column.__set_name__(default, cls, name)
54
55
 
55
- default.dtype = field_type # COMMENT: Useful for setting the dtype variable after instantiation.
56
56
  fields.append(Field[TProp](name, field_type, default))
57
57
 
58
58
  # Update __annotations__ to create Columns
59
59
  cls.__annotations__[name] = default
60
+ setattr(cls, name, default)
60
61
  return fields
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
  from decimal import Decimal
3
- from typing import Any, Optional, Type, dataclass_transform, overload, TYPE_CHECKING
3
+ from typing import Any, Optional, Type, dataclass_transform
4
4
  import base64
5
5
  import datetime
6
6
  import json
@@ -8,21 +8,15 @@ import json
8
8
  import shapely as sph
9
9
 
10
10
 
11
- from .column import Column
12
- from .dtypes import get_query_clausule
11
+ from ormlambda.sql import Column
12
+ from ormlambda.sql import ForeignKey
13
+ from ormlambda.sql.dtypes import get_query_clausule
13
14
  from .fields import get_fields
14
- from .foreign_key import ForeignKey, TableInfo
15
- from .module_tree.dfs_traversal import DFSTraversal
16
-
17
- if TYPE_CHECKING:
18
- from .fields import Field
15
+ from ormlambda.utils.module_tree.dfs_traversal import DFSTraversal
19
16
 
20
17
 
21
18
  @dataclass_transform()
22
19
  def __init_constructor__[T](cls: Type[T]) -> Type[T]:
23
- # create '__properties_mapped__' dictionary for each Table to avoid shared information
24
- # TODOL: I don't know if it's better to create a global dictionary like in commit '7de69443d7a8e7264b8d5d604c95da0e5d7e9cc0'
25
- setattr(cls, "__properties_mapped__", {})
26
20
  fields = get_fields(cls)
27
21
 
28
22
  locals_: dict[str, Any] = {}
@@ -34,21 +28,20 @@ def __init_constructor__[T](cls: Type[T]) -> Type[T]:
34
28
  continue
35
29
 
36
30
  locals_[field.type_name] = field.type_
37
- locals_[field.default_name] = field.default.column_value
31
+ locals_[field.default_name] = None
38
32
 
39
33
  init_args.append(field.init_arg)
40
34
  assignments.append(field.assginment)
41
- __create_properties(cls, field)
42
35
 
43
36
  string_locals_ = ", ".join(locals_)
44
37
  string_init_args = ", ".join(init_args)
45
- string_assignments = "\n\t\t".join(assignments)
38
+ string_assignments = "".join([f"\n\t\t{x}" for x in assignments])
46
39
 
47
40
  wrapper_fn = "\n".join(
48
41
  [
49
42
  f"def wrapper({string_locals_}):",
50
43
  f"\n\tdef __init__({string_init_args}):",
51
- f"\n\t\t{string_assignments}",
44
+ string_assignments,
52
45
  "\treturn __init__",
53
46
  ]
54
47
  )
@@ -62,21 +55,6 @@ def __init_constructor__[T](cls: Type[T]) -> Type[T]:
62
55
  return cls
63
56
 
64
57
 
65
- def __create_properties(cls: Type["Table"], field: Field) -> property:
66
- _name: str = f"_{field.name}"
67
-
68
- # we need to get Table attributes (Column class) and then called __getattribute__ or __setattr__ to make changes inside of Column
69
- prop = property(
70
- fget=lambda self: getattr(self, _name).__getattribute__("column_value"),
71
- fset=lambda self, value: getattr(self, _name).__setattr__("column_value", value),
72
- )
73
-
74
- # set property in public name
75
- setattr(cls, field.name, prop)
76
- cls.__properties_mapped__[prop] = field.name
77
- return None
78
-
79
-
80
58
  class TableMeta(type):
81
59
  def __new__[T](cls: "Table", name: str, bases: tuple, dct: dict[str, Any]) -> Type[T]:
82
60
  """
@@ -95,27 +73,12 @@ class TableMeta(type):
95
73
  if not isinstance(cls_object.__table_name__, str):
96
74
  raise Exception(f"class variable '__table_name__' of '{cls_object.__name__}' class must be 'str'")
97
75
 
98
- TableMeta.__add_to_ForeignKey(cls_object)
99
76
  self = __init_constructor__(cls_object)
100
77
  return self
101
78
 
102
79
  def __repr__(cls: "Table") -> str:
103
80
  return f"{TableMeta.__name__}: {cls.__table_name__}"
104
81
 
105
- @staticmethod
106
- def __add_to_ForeignKey(cls: "Table") -> None:
107
- """
108
- When creating a Table class, we cannot pass the class itself as a parameter in a function that initializes a class variable.
109
- To fix this, we first add the table name as key and then, we add the class itself in the TableInfo class.
110
- """
111
- if table_info := ForeignKey.MAPPED.get(cls.__table_name__, None):
112
- table_info.table_object = cls
113
- else:
114
- ForeignKey.MAPPED[cls.__table_name__] = TableInfo()
115
- ForeignKey.MAPPED[cls.__table_name__].table_object = cls
116
-
117
- return None
118
-
119
82
 
120
83
  @dataclass_transform(eq_default=False)
121
84
  class Table(metaclass=TableMeta):
@@ -130,7 +93,7 @@ class Table(metaclass=TableMeta):
130
93
  >>> class Address(Table):
131
94
  >>> __table_name__ = "address"
132
95
 
133
- >>> address_id: int = Column[int](is_primary_key=True)
96
+ >>> address_id: int = Column(int, is_primary_key=True)
134
97
  >>> address: str
135
98
  >>> address2: str
136
99
  >>> district: str
@@ -138,20 +101,19 @@ class Table(metaclass=TableMeta):
138
101
  >>> postal_code: datetime
139
102
  >>> phone: str
140
103
  >>> location: datetime
141
- >>> last_update: datetime = Column[datetime](is_auto_generated=True)
104
+ >>> last_update: datetime = Column(datetime, is_auto_generated=True)
142
105
 
143
- >>> city = ForeignKey["Address", City](__table_name__, City, lambda a, c: a.city_id == c.city_id)
106
+ >>> city = ForeignKey["Address", City](City, lambda a, c: a.city_id == c.city_id)
144
107
  """
145
108
 
146
109
  __table_name__: str = ...
147
- __properties_mapped__: dict[property, str] = ...
148
110
 
149
111
  def __str__(self) -> str:
150
112
  params = self.to_dict()
151
113
  return json.dumps(params, ensure_ascii=False, indent=2)
152
114
 
153
- def __getattr__[T](self, __name: str) -> Column[T]:
154
- return self.__dict__.get(__name, None)
115
+ def __getattr__[T](self, _name: str) -> Column[T]:
116
+ return self.__dict__.get(_name, None)
155
117
 
156
118
  def __repr__(self: "Table") -> str:
157
119
  def __cast_long_variables(value: Any):
@@ -165,6 +127,12 @@ class Table(metaclass=TableMeta):
165
127
  equal_loop = ["=".join((x, __cast_long_variables(y))) for x, y in dicc.items()]
166
128
  return f'{self.__class__.__name__}({", ".join(equal_loop)})'
167
129
 
130
+ def __getitem__[TProp](self, value: str | Column[TProp]) -> Optional[TProp]:
131
+ name = value if isinstance(value, str) else value.column_name
132
+ if hasattr(self, name):
133
+ return getattr(self, name)
134
+ return None
135
+
168
136
  def to_dict(self) -> dict[str, str | int]:
169
137
  dicc: dict[str, Any] = {}
170
138
  for x in self.__annotations__:
@@ -190,17 +158,22 @@ class Table(metaclass=TableMeta):
190
158
  return transform_map[dtype](_value)
191
159
  return _value
192
160
 
193
- def get_pk(self) -> Optional[Column]:
194
- for col_name in self.__annotations__.keys():
195
- private_col = f"_{col_name}"
196
- col_obj = getattr(self, private_col)
197
- if isinstance(col_obj, Column) and col_obj.is_primary_key:
198
- return col_obj
161
+ @classmethod
162
+ def get_pk(cls) -> Optional[Column]:
163
+ for obj in cls.__dict__.values():
164
+ if isinstance(obj, Column) and obj.is_primary_key:
165
+ return obj
199
166
  return None
200
167
 
201
168
  @classmethod
202
169
  def get_columns(cls) -> tuple[str, ...]:
203
- return tuple(cls.__annotations__.keys())
170
+ return tuple([x for x in cls.__annotations__.values() if isinstance(x, Column)])
171
+
172
+ @classmethod
173
+ def get_column[TProp](cls,name:str) -> Column[TProp]:
174
+ for key,value in cls.__annotations__.items():
175
+ if name == key:
176
+ return value
204
177
 
205
178
  @classmethod
206
179
  def create_table_query(cls) -> str:
@@ -218,16 +191,17 @@ class Table(metaclass=TableMeta):
218
191
  It's imperative to instantiate cls() to initialize the 'Table' object and create private variables that will be Column objects.
219
192
  Otherwise, we only can access to property method
220
193
  """
221
- table_init_ = cls()
222
- annotations: dict[str, Column] = table_init_.__annotations__
194
+ annotations: dict[str, Column] = cls.__annotations__
223
195
  all_columns: list = []
224
- for col_name in annotations.keys():
225
- col_object: Column = getattr(table_init_, f"_{col_name}")
226
- all_columns.append(get_query_clausule(col_object))
196
+ for col_obj in annotations.values():
197
+ all_columns.append(get_query_clausule(col_obj))
227
198
  return all_columns
228
199
 
229
200
  @classmethod
230
201
  def find_dependent_tables(cls) -> tuple["Table", ...]:
202
+ """Work in progress"""
203
+ return
204
+
231
205
  # TODOL: Dive into new way to return dependent tables
232
206
  def get_involved_tables(graph: dict[Table, list[Table]], table_name: str) -> None:
233
207
  """
@@ -266,33 +240,11 @@ class Table(metaclass=TableMeta):
266
240
  return False
267
241
 
268
242
  @classmethod
269
- def get_property_name(cls, _property: property) -> str:
270
- name: str = cls.__properties_mapped__.get(_property, None)
271
- if not name:
272
- raise KeyError(f"Class '{cls.__name__}' has not propery '{_property}' mapped.")
273
- return name
243
+ def table_alias(cls, column: Optional[str] = None) -> str:
244
+ if column:
245
+ return f"`{cls.__table_name__}_{column}`"
246
+ return cls.__table_name__
274
247
 
275
- @overload
276
248
  @classmethod
277
- def get_column(cls, column: str) -> Column: ...
278
- @overload
279
- @classmethod
280
- def get_column(cls, column: property) -> Column: ...
281
- @overload
282
- @classmethod
283
- def get_column[TProp](cls, column: property, value: TProp) -> Column[TProp]: ...
284
- @overload
285
- @classmethod
286
- def get_column[TProp](cls, column: str, value: TProp) -> Column[TProp]: ...
287
- @classmethod
288
- def get_column[TProp](cls, column: str | property, value: Optional[TProp] = None) -> Column[TProp]:
289
- if isinstance(column, property):
290
- _column = cls.get_property_name(column)
291
- elif isinstance(column, str) and column in cls.get_columns():
292
- _column = column
293
- else:
294
- raise ValueError(f"'Column' param with value'{column}' is not expected.")
295
-
296
- instance_table: Table = cls(**{_column: value})
297
-
298
- return getattr(instance_table, f"_{_column}")
249
+ def foreign_keys(cls) -> dict[str, ForeignKey]:
250
+ return {key: value for key, value in cls.__dict__.items() if isinstance(value, ForeignKey)}
ormlambda/sql/types.py ADDED
@@ -0,0 +1,25 @@
1
+ import typing as tp
2
+
3
+
4
+ if tp.TYPE_CHECKING:
5
+ from ormlambda import Table, Column, ForeignKey
6
+ from ormlambda.sql.comparer import Comparer
7
+ from ormlambda import ConditionType as ConditionEnum
8
+ from ormlambda.common.enums.join_type import JoinType
9
+
10
+
11
+ type AsteriskType = str
12
+ type TableType[T: Table] = tp.Type[T] | ForeignKey[T]
13
+ type ColumnType[TProp] = TProp | Column[TProp] | AsteriskType | tuple[Column]
14
+ type AliasType[T] = tp.Optional[str | tp.Callable[[T], str]]
15
+
16
+ # region Comparer Types
17
+ type ComparerType = tp.Literal["=", "!=", "<", "<=", ">", ">=", "in"]
18
+ type ConditionType[TProp] = Comparer | ColumnType[TProp]
19
+ type UnionType = tp.Literal["AND", "OR", ""]
20
+ type ComparerTypes = ComparerType | UnionType | ConditionEnum
21
+ # endregion
22
+
23
+ type TupleJoinType[T] = tuple[Comparer[T], JoinType]
24
+
25
+ ASTERISK: AsteriskType = "*"
@@ -0,0 +1,2 @@
1
+ from .base_statement import BaseStatement # noqa: F401
2
+ from .types import OrderType # noqa: F401