ormlambda 2.0.2__py3-none-any.whl → 2.6.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.
@@ -1,172 +1,45 @@
1
- from typing import Callable, Optional, Type, override
2
- import inspect
1
+ from typing import override, Type, Callable, TYPE_CHECKING
3
2
 
4
- from ormlambda.utils.lambda_disassembler import TreeInstruction, TupleInstruction, NestedElement
5
- from ormlambda.components.select import ISelect, TableColumn
6
- from ormlambda import Table, ForeignKey
7
- from ormlambda.utils.table_constructor import TableMeta
3
+ from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase
4
+ from ormlambda.common.enums.join_type import JoinType
8
5
 
9
- from . import JoinSelector, JoinType
6
+ if TYPE_CHECKING:
7
+ from ormlambda import Table
10
8
 
11
9
 
12
- class SelectQuery[T: Table, *Ts](ISelect):
13
- SELECT = "SELECT"
10
+ class Select[T: Type[Table]](DecompositionQueryBase[T]):
11
+ CLAUSE: str = "SELECT"
14
12
 
15
13
  def __init__(
16
14
  self,
17
- tables: T | tuple[T, *Ts] = (),
18
- select_lambda: Optional[Callable[[T, *Ts], None]] = lambda: None,
15
+ table: T,
16
+ lambda_query: Callable[[T], tuple] = lambda x: x,
19
17
  *,
18
+ alias: bool = False,
19
+ alias_name: str | None = None,
20
20
  by: JoinType = JoinType.INNER_JOIN,
21
21
  ) -> None:
22
- if not isinstance(tables, tuple):
23
- tables = tuple([tables])
24
-
25
- self._first_table: T = tables[0]
26
- self._tables: tuple[T, *Ts] = tables
27
- self._select_lambda: Optional[Callable[[T, *Ts], None]] = select_lambda
28
- self._by: JoinType = by
29
-
30
- self._tables_heritage: list[tuple[Table, Table]] = []
31
- self._lambda_var_to_table_dicc: dict[str, Table] = self._assign_lambda_variables_to_table(select_lambda)
32
-
33
- self._select_list: list[TableColumn] = self._rename_recursive_column_list(select_lambda)
34
-
35
- def _rename_recursive_column_list(self, _lambda: Optional[Callable[[T], None]]) -> list[TableColumn]:
36
- """
37
- Recursive function tu replace variable names by Select Query
38
-
39
- lambda a: (a.pk_address, a.city.pk_city, a.city.country.pk_country)
40
-
41
- >>> # convert lambda expression into list of values
42
- >>> select_list = [
43
- >>> "a.pk_address",
44
- >>> "a.city",
45
- >>> "a.city.pk_city",
46
- >>> "a.city.country",
47
- >>> "a.city.country.pk_country",
48
- >>> ]
49
- >>> result = _rename_recursive_column_list(select_list)
50
- >>> print(result)
51
- >>> # result = [
52
- >>> # "address.pk_address"
53
- >>> # "city.*"
54
- >>> # "city.pk_city"
55
- >>> # "country.*"
56
- >>> # "country.pk_country"
57
- ]
58
- """
59
- instruction_list: list[TupleInstruction] = TreeInstruction(_lambda).to_list()
60
- column_list: list[TableColumn] = []
61
-
62
- for ti in instruction_list:
63
- obj = self._lambda_var_to_table_dicc[ti.var]
64
-
65
- var = obj.__table_name__
66
- new_nested = ti.nested_element.parents
67
- new_nested[0] = var
68
- ti = TupleInstruction(var, NestedElement(new_nested))
69
- self._get_parents(obj, ti, column_list)
70
- return column_list
71
-
72
- def _get_parents(self, tbl_obj: Table, tuple_inst: TupleInstruction, column_list: list[TableColumn]) -> None:
73
- if self._user_want_all_col(tbl_obj, tuple_inst):
74
- column_list.extend(list(TableColumn.all_columns(tbl_obj)))
75
- return None
76
-
77
- # if the 'last_el' var is a property, we'll know the user will want retrieve a column of the same instance of the 'tbl_obj'. Otherwise the user will want to get a column of the other instance
78
- last_el: str = tuple_inst.nested_element.name
79
- if self._user_want_column_of_the_same_table(tbl_obj, tuple_inst):
80
- return column_list.append(TableColumn(tbl_obj, last_el))
81
-
82
- parents: list[str] = tuple_inst.nested_element.parents
83
- first_el = parents[1]
84
- new_ti = TupleInstruction(first_el, NestedElement[str](parents[1:])) # create new TupleInstruction from the second parent to the top
85
- new_attr = self.get_attribute_of(tbl_obj, first_el) # could be Table or property
86
-
87
- self._add_fk_relationship(tbl_obj, new_attr)
88
- return self._get_parents(new_attr, new_ti, column_list)
89
-
90
- def _add_fk_relationship(self, t1: Table, t2: Table) -> None:
91
- tuple_ = tuple([t1, t2])
92
- if tuple_ not in self._tables_heritage:
93
- self._tables_heritage.append(tuple_)
94
- return None
95
-
96
- @staticmethod
97
- def _user_want_all_col(tbl: Table, ti: TupleInstruction) -> bool:
98
- """
99
- if ti.nested_element.parents length is 1 says that the element is the table itself (table.*)
100
- """
101
- return issubclass(tbl.__class__, Table | TableMeta) and len(ti.nested_element.parents) == 1
102
-
103
- def _user_want_column_of_the_same_table(self, table: Table, ti: TupleInstruction) -> bool:
104
- last_el: str = ti.nested_element.name
105
- first_el = ti.nested_element.parents[1]
106
-
107
- table_attr = self.get_attribute_of(table, first_el)
108
-
109
- return last_el in table.__dict__ and isinstance(table_attr, property)
110
-
111
- @staticmethod
112
- def get_attribute_of[TProp: Table](table: TProp, _value: str) -> Optional[TProp | property]:
113
- try:
114
- return getattr(table.__class__, _value)
115
- except Exception:
116
- return getattr(table, _value, None)
117
-
118
- def _assign_lambda_variables_to_table(self, _lambda: Callable[[T], None]) -> dict[str, Type[Table]]:
119
- """
120
- return a dictionary with the lambda's parameters as keys and Type[Table] as the values
121
-
122
-
123
- >>> res = _assign_lambda_variables_to_table(lambda a,ci,co: ...)
124
- >>> print(res)
125
- >>> # {
126
- >>> # "a": Address,
127
- >>> # "ci": City,
128
- >>> # "co": Country,
129
- >>> # }
130
- """
131
- lambda_vars = tuple(inspect.signature(_lambda).parameters)
132
-
133
- dicc: dict[str, Table] = {}
134
- for i in range(len(lambda_vars)):
135
- dicc[lambda_vars[i]] = self._tables[i]
136
- return dicc
137
-
138
- def _convert_select_list(self) -> str:
139
- self._select_list = self._select_list if self._select_list else tuple(TableColumn.all_columns(self._first_table))
140
-
141
- return ", ".join(col.column for col in self._select_list)
22
+ super().__init__(
23
+ table,
24
+ lambda_query,
25
+ alias=alias,
26
+ alias_name=alias_name,
27
+ by=by,
28
+ )
29
+
30
+ # @classmethod
31
+ # def alias_children_resolver[Tclause: Type[Table]](self, clause_info: ClauseInfo[Tclause]):
32
+ # return f"{clause.table.__table_name__}_{name}"
142
33
 
143
34
  @override
144
35
  @property
145
36
  def query(self) -> str:
146
- select_str = self._convert_select_list()
147
- query: str = f"{self.SELECT} {select_str} FROM {self._first_table.__table_name__}"
37
+ col: str = ", ".join([x.query for x in self.all_clauses])
38
+ query: str = f"{self.CLAUSE} {col} FROM {self._table.__table_name__}"
39
+ alias = ""
148
40
 
149
- involved_tables = self.get_involved_tables()
150
- if not involved_tables:
151
- return query
41
+ query += alias
42
+ if self.has_foreign_keys:
43
+ query += " " + self.stringify_foreign_key(" ")
152
44
 
153
- sub_query: str = ""
154
- for l_tbl, r_tbl in involved_tables:
155
- join = JoinSelector(l_tbl, r_tbl, by=self._by, where=ForeignKey.MAPPED[l_tbl.__table_name__].referenced_tables[r_tbl.__table_name__].relationship)
156
- sub_query += f" {join.query}"
157
-
158
- query += sub_query
159
45
  return query
160
-
161
- @override
162
- @property
163
- def select_list(self) -> list[TableColumn]:
164
- return self._select_list
165
-
166
- @override
167
- @property
168
- def tables_heritage(self) -> list[tuple[Table, Table]]:
169
- return self._tables_heritage
170
-
171
- def get_involved_tables(self) -> tuple[tuple[Table, Table]]:
172
- return tuple(self._tables_heritage)
@@ -1,4 +1,4 @@
1
- from typing import Any, Callable, Optional, override
1
+ from typing import Any, Callable, Optional, override, Type
2
2
  import inspect
3
3
 
4
4
  from ormlambda.common.enums import ConditionType
@@ -19,7 +19,7 @@ class WhereConditionByArg[TProp1, TProp2](IQuery):
19
19
  return f"WHERE {self.cond1} {self.symbol.value} {self.cond2}"
20
20
 
21
21
 
22
- class WhereCondition[*Inst](AbstractWhere):
22
+ class WhereCondition[T: Type[Table], *Inst](AbstractWhere):
23
23
  """
24
24
  The purpose of this class is to create 'WHERE' condition queries properly.
25
25
 
@@ -0,0 +1,3 @@
1
+ from .max import Max # noqa: F401
2
+ from .concat import Concat # noqa: F401
3
+ from .group_by import GroupBy # noqa: F401
@@ -0,0 +1,41 @@
1
+ from ormlambda.common.interfaces.IAggregate import IAggregate
2
+ from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase, ClauseInfo
3
+
4
+
5
+ import typing as tp
6
+ from ormlambda.common.enums.join_type import JoinType
7
+
8
+ if tp.TYPE_CHECKING:
9
+ from ormlambda import Table
10
+
11
+
12
+ class Concat[T: tp.Type[Table]](DecompositionQueryBase[T], IAggregate[T]):
13
+ CLAUSE = "CONCAT"
14
+
15
+ def __init__[*Ts](
16
+ self,
17
+ table: T,
18
+ lambda_query: str | tp.Callable[[T], tuple[*Ts]],
19
+ *,
20
+ alias: bool = True,
21
+ alias_name: str = "CONCAT",
22
+ by: JoinType = JoinType.INNER_JOIN,
23
+ ) -> None:
24
+ super().__init__(
25
+ table,
26
+ lambda_query,
27
+ alias=alias,
28
+ alias_name=alias_name,
29
+ by=by,
30
+ )
31
+
32
+ def alias_children_resolver[Tclause: tp.Type[Table]](self, clause_info: ClauseInfo[Tclause]):
33
+ if isinstance(clause_info._row_column, IAggregate):
34
+ return clause_info._row_column.alias
35
+ return None
36
+
37
+ @property
38
+ def query(self) -> str:
39
+ col: str = ", ".join([x.query for x in self.all_clauses])
40
+
41
+ return f"{self.CLAUSE}({col})"
@@ -0,0 +1,37 @@
1
+ import typing as tp
2
+ from ormlambda.common.enums.join_type import JoinType
3
+ from ormlambda.common.abstract_classes.decomposition_query import ClauseInfo, DecompositionQueryBase
4
+ from ormlambda.common.interfaces.IAggregate import IAggregate
5
+ from ormlambda import Table
6
+
7
+
8
+ class GroupBy[T: tp.Type[Table], TProp](DecompositionQueryBase[T], IAggregate[T]):
9
+ CLAUSE: str = "GROUP BY"
10
+
11
+ def __init__(
12
+ self,
13
+ table: T,
14
+ column: tp.Callable[[T], TProp],
15
+ *,
16
+ alias: bool = True,
17
+ alias_name: str | None = None,
18
+ by: JoinType = JoinType.INNER_JOIN,
19
+ ) -> None:
20
+ super().__init__(
21
+ table,
22
+ lambda_query=column,
23
+ alias=alias,
24
+ alias_name=alias_name,
25
+ by=by,
26
+ )
27
+
28
+ self._column: TProp = column
29
+
30
+ def alias_children_resolver[Tclause: tp.Type[Table]](self, clause_info: ClauseInfo[Tclause]):
31
+ return None
32
+
33
+ @property
34
+ def query(self) -> str:
35
+ col: str = ", ".join([x.query for x in self.all_clauses])
36
+
37
+ return f"{self.CLAUSE} {col}"
@@ -0,0 +1,39 @@
1
+ from ormlambda.common.interfaces import IAggregate
2
+ import typing as tp
3
+
4
+ from ormlambda.common.abstract_classes.decomposition_query import DecompositionQueryBase, ClauseInfo
5
+
6
+ if tp.TYPE_CHECKING:
7
+ from ormlambda import Table
8
+
9
+
10
+ class Max[T: tp.Type[Table]](DecompositionQueryBase[T], IAggregate[T]):
11
+ NAME: str = "MAX"
12
+
13
+ @tp.overload
14
+ def __init__[T: tp.Type[Table]](self, table: T, column: tp.Callable[[T], tp.Any], *, alias: bool = True, alias_name: str = "max") -> None: ...
15
+
16
+ def __init__(
17
+ self,
18
+ table: T,
19
+ column: str | tp.Callable[[T], tuple],
20
+ *,
21
+ alias: bool = True,
22
+ alias_name: str = "max",
23
+ ) -> None:
24
+ super().__init__(
25
+ table,
26
+ lambda_query=column,
27
+ alias=alias,
28
+ alias_name=alias_name,
29
+ )
30
+
31
+ def alias_children_resolver[Tclause: tp.Type[Table]](self, clause_info: ClauseInfo[Tclause]):
32
+ if isinstance(clause_info._row_column, IAggregate):
33
+ return clause_info._row_column.alias
34
+ return None
35
+
36
+ @property
37
+ def query(self) -> str:
38
+ col = ", ".join([x.query for x in self.all_clauses])
39
+ return f"{self.NAME}({col})"
@@ -81,8 +81,10 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
81
81
  self.connect()
82
82
  try:
83
83
  foo = func(self, *args, **kwargs)
84
- finally:
84
+ except Exception as e:
85
85
  self.connection.rollback()
86
+ raise e
87
+ finally:
86
88
  self.close_connection()
87
89
  return foo
88
90
 
@@ -94,7 +96,8 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
94
96
  self._connection: PooledMySQLConnection = None
95
97
 
96
98
  def __create_MySQLConnectionPool(self):
97
- return MySQLConnectionPool(pool_name="mypool",pool_size=10, **self._data_config)
99
+ return MySQLConnectionPool(pool_name="mypool", pool_size=10, **self._data_config)
100
+
98
101
  @override
99
102
  def is_connected(self) -> bool:
100
103
  return self._connection._cnx is not None if self._connection else False
@@ -122,7 +125,7 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
122
125
  - flavour: Type[TFlavour]: Useful to return tuple of any Iterable type as dict,set,list...
123
126
  """
124
127
 
125
- with self._connection.cursor(buffered=True) as cursor:
128
+ with self._connection._cnx.cursor(buffered=True) as cursor:
126
129
  cursor.execute(query)
127
130
  values: list[tuple] = cursor.fetchall()
128
131
  columns: tuple[str] = cursor.column_names
@@ -145,33 +148,33 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
145
148
  queries_list: list[str] = module_tree.get_queries()
146
149
 
147
150
  for query in queries_list:
148
- with self._connection.cursor(buffered=True) as cursor:
151
+ with self._connection._cnx.cursor(buffered=True) as cursor:
149
152
  cursor.execute(query)
150
- self._connection.commit()
153
+ self._connection._cnx.commit()
151
154
  return None
152
155
 
153
156
  @override
154
157
  @get_connection
155
158
  def executemany_with_values(self, query: str, values) -> None:
156
- with self._connection.cursor(buffered=True) as cursor:
159
+ with self._connection._cnx.cursor(buffered=True) as cursor:
157
160
  cursor.executemany(query, values)
158
- self._connection.commit()
161
+ self._connection._cnx.commit()
159
162
  return None
160
163
 
161
164
  @override
162
165
  @get_connection
163
166
  def execute_with_values(self, query: str, values) -> None:
164
- with self._connection.cursor(buffered=True) as cursor:
167
+ with self._connection._cnx.cursor(buffered=True) as cursor:
165
168
  cursor.execute(query, values)
166
- self._connection.commit()
169
+ self._connection._cnx.commit()
167
170
  return None
168
171
 
169
172
  @override
170
173
  @get_connection
171
174
  def execute(self, query: str) -> None:
172
- with self._connection.cursor(buffered=True) as cursor:
175
+ with self._connection._cnx.cursor(buffered=True) as cursor:
173
176
  cursor.execute(query)
174
- self._connection.commit()
177
+ self._connection._cnx.commit()
175
178
  return None
176
179
 
177
180
  @override
@@ -182,7 +185,7 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
182
185
  @get_connection
183
186
  def database_exists(self, name: str) -> bool:
184
187
  query = "SHOW DATABASES LIKE %s;"
185
- with self._connection.cursor(buffered=True) as cursor:
188
+ with self._connection._cnx.cursor(buffered=True) as cursor:
186
189
  cursor.execute(query, (name,))
187
190
  res = cursor.fetchmany(1)
188
191
  return len(res) > 0
@@ -194,11 +197,11 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
194
197
  @override
195
198
  @get_connection
196
199
  def table_exists(self, name: str) -> bool:
197
- if not self._connection.database:
200
+ if not self._connection._cnx.database:
198
201
  raise Exception("No database selected")
199
202
 
200
203
  query = "SHOW TABLES LIKE %s;"
201
- with self._connection.cursor(buffered=True) as cursor:
204
+ with self._connection._cnx.cursor(buffered=True) as cursor:
202
205
  cursor.execute(query, (name,))
203
206
  res = cursor.fetchmany(1)
204
207
  return len(res) > 0
@@ -219,4 +222,4 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
219
222
  @database.setter
220
223
  def database(self, value: str) -> None:
221
224
  self._data_config["database"] = value
222
- self._pool = self.__create_MySQLConnectionPool()
225
+ self._pool = self.__create_MySQLConnectionPool()
@@ -3,15 +3,10 @@ from typing import override, Type, TYPE_CHECKING, Any, Callable, Optional
3
3
 
4
4
  if TYPE_CHECKING:
5
5
  from ormlambda import Table
6
- from ormlambda.components.select import ISelect
7
6
  from ormlambda.components.where.abstract_where import AbstractWhere
8
7
  from ormlambda.common.interfaces.IStatements import OrderType
9
8
  from ormlambda.common.interfaces import IQuery, IRepositoryBase, IStatements_two_generic
10
- from src.ormlambda.common.interfaces.IRepositoryBase import TypeExists
11
-
12
- from ormlambda.databases.my_sql.clauses.select import SelectQuery
13
- from ormlambda.databases.my_sql.clauses.count import CountQuery
14
-
9
+ from ormlambda.common.interfaces.IRepositoryBase import TypeExists
15
10
 
16
11
  from ormlambda import AbstractSQLStatements
17
12
  from .clauses import DeleteQuery
@@ -20,11 +15,13 @@ from .clauses import JoinSelector
20
15
  from .clauses import LimitQuery
21
16
  from .clauses import OffsetQuery
22
17
  from .clauses import OrderQuery
23
- from .clauses import SelectQuery
18
+ from .clauses.select import Select
19
+
24
20
  from .clauses import UpsertQuery
25
21
  from .clauses import UpdateQuery
26
22
  from .clauses import WhereCondition
27
- from .clauses import CountQuery
23
+ from .clauses import Count
24
+ from .clauses import GroupBy
28
25
 
29
26
  from mysql.connector import MySQLConnection, errors, errorcode
30
27
 
@@ -129,10 +126,10 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
129
126
  return self
130
127
 
131
128
  @override
132
- def count(self) -> int:
133
- count_select: IQuery = CountQuery(self._model)
129
+ def count(self, selection: Callable[[T], tuple] = lambda x: "*") -> int:
130
+ count_select: IQuery = Select[T](self._model, lambda x: Count[T](self._model, selection))
134
131
  self._query_list["select"].append(count_select)
135
- query = self.build()
132
+ query = self._build()
136
133
  return self.repository.read_sql(query)[0][0]
137
134
 
138
135
  @override
@@ -165,10 +162,10 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
165
162
  if flavour:
166
163
  return result
167
164
  return () if not result else result[0]
168
- select: ISelect = SelectQuery(self._model, select_lambda=selector, by=by)
165
+ select = Select[T](self._model, lambda_query=selector, by=by, alias=False)
169
166
  self._query_list["select"].append(select)
170
167
 
171
- query: str = self.build()
168
+ query: str = self._build()
172
169
  if flavour:
173
170
  result = self._return_flavour(query, flavour)
174
171
  if issubclass(flavour, tuple) and isinstance(selector(self._model), property):
@@ -194,12 +191,17 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
194
191
  return tuple([res[0] for res in response])
195
192
 
196
193
  @override
197
- def build(self) -> str:
194
+ def group_by[TRepo, *Ts](self, column: Callable[[T], TRepo], select_query: Callable[[T], tuple[*Ts]]) -> tuple[tuple[*Ts]]:
195
+ return GroupBy[T, TRepo, tuple[*Ts]](self._model, column, select_query)
196
+
197
+ @override
198
+ def _build(self) -> str:
198
199
  query: str = ""
199
200
 
200
- self.__create_necessary_inner_join()
201
+ # self.__create_necessary_inner_join()
201
202
  for x in self.__order__:
202
- if sub_query := self._query_list.get(x, None):
203
+ sub_query: Optional[list[IQuery]] = self._query_list.get(x, None)
204
+ if sub_query is not None:
203
205
  if isinstance(sub_query[0], WhereCondition):
204
206
  query_ = self.__build_where_clause(sub_query)
205
207
 
@@ -225,19 +227,3 @@ class MySQLStatements[T: Table](AbstractSQLStatements[T, MySQLConnection]):
225
227
  and_, clause = q.split(" ", maxsplit=1)
226
228
  query += f" {and_} ({clause})"
227
229
  return query
228
-
229
- def __create_necessary_inner_join(self) -> None:
230
- # When we applied filters in any table that we wont select any column, we need to add manually all neccessary joins to achieve positive result.
231
- if "where" not in self._query_list:
232
- return None
233
-
234
- where: AbstractWhere = self._query_list["where"][0]
235
- involved_tables = where.get_involved_tables()
236
-
237
- select: ISelect = self._query_list["select"][0]
238
- if not involved_tables or (set(involved_tables) == set(select.tables_heritage)):
239
- return None
240
-
241
- for l_tbl, r_tbl in involved_tables:
242
- # FIXME [ ]: Checked what function was called by the self.join method before the change
243
- self.join(l_tbl, r_tbl, by="INNER JOIN")
ormlambda/model_base.py CHANGED
@@ -24,6 +24,8 @@ class BaseModel[T: Type[Table]]:
24
24
  # region Constructor
25
25
 
26
26
  def __new__[TRepo](cls, model: T, repository: IRepositoryBase[TRepo]) -> IStatements_two_generic[T, TRepo]:
27
+ if repository is None:
28
+ raise ValueError("`None` cannot be passed to the `repository` attribute when calling the `BaseModel` class")
27
29
  cls: AbstractSQLStatements[T, TRepo] = cls.statements_dicc.get(type(repository), None)
28
30
 
29
31
  if not cls:
@@ -1,7 +1,7 @@
1
1
  import base64
2
2
  import datetime
3
3
  from decimal import Decimal
4
- from typing import Any, Iterable, Optional, Type, dataclass_transform
4
+ from typing import Any, Iterable, Optional, Type, dataclass_transform, get_type_hints
5
5
  import json
6
6
 
7
7
  from .dtypes import get_query_clausule
@@ -14,9 +14,9 @@ MISSING = Column()
14
14
 
15
15
 
16
16
  class Field:
17
- def __init__(self, name: str, type_: type, default: object) -> None:
17
+ def __init__(self, name: str, type_: Type, default: object) -> None:
18
18
  self.name: str = name
19
- self.type_: type = type_
19
+ self.type_: Type = type_
20
20
  self.default: Column = default
21
21
 
22
22
  def __repr__(self) -> str:
@@ -54,7 +54,8 @@ def delete_special_variables(dicc: dict[str, object]) -> None:
54
54
 
55
55
 
56
56
  def get_fields[T](cls: Type[T]) -> Iterable[Field]:
57
- annotations = getattr(cls, "__annotations__", {})
57
+ # COMMENT: Used the 'get_type_hints' method to resolve typing when 'from __future__ import annotations' is in use
58
+ annotations = {key: val for key, val in get_type_hints(cls).items() if not key.startswith("_")}
58
59
 
59
60
  # delete_special_variables(annotations)
60
61
  fields = []
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ormlambda
3
- Version: 2.0.2
3
+ Version: 2.6.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