ormlambda 2.0.2__py3-none-any.whl → 2.6.1__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})"
@@ -77,42 +77,27 @@ class Response[TFlavour, *Ts]:
77
77
  class MySQLRepository(IRepositoryBase[MySQLConnection]):
78
78
  def get_connection(func: Callable[..., Any]):
79
79
  @functools.wraps(func)
80
- def wrapper(self: IRepositoryBase[MySQLConnection], *args, **kwargs):
81
- self.connect()
82
- try:
83
- foo = func(self, *args, **kwargs)
84
- finally:
85
- self.connection.rollback()
86
- self.close_connection()
87
- return foo
80
+ def wrapper(self: MySQLRepository, *args, **kwargs):
81
+ with self._pool.get_connection() as cnx:
82
+ try:
83
+ foo = func(self, cnx, *args, **kwargs)
84
+ return foo
85
+ except Exception as e:
86
+ self.connection.rollback()
87
+ raise e
88
88
 
89
89
  return wrapper
90
90
 
91
91
  def __init__(self, **kwargs: Any) -> None:
92
92
  self._data_config: dict[str, Any] = kwargs
93
93
  self._pool: MySQLConnectionPool = self.__create_MySQLConnectionPool()
94
- self._connection: PooledMySQLConnection = None
95
94
 
96
95
  def __create_MySQLConnectionPool(self):
97
- return MySQLConnectionPool(pool_name="mypool",pool_size=10, **self._data_config)
98
- @override
99
- def is_connected(self) -> bool:
100
- return self._connection._cnx is not None if self._connection else False
101
-
102
- @override
103
- def connect(self) -> None:
104
- self._connection = self._pool.get_connection()
105
- return None
106
-
107
- @override
108
- def close_connection(self) -> None:
109
- if self.is_connected():
110
- self._connection.close()
111
- return None
96
+ return MySQLConnectionPool(pool_name="mypool", pool_size=10, **self._data_config)
112
97
 
113
98
  @override
114
99
  @get_connection
115
- def read_sql[TFlavour](self, query: str, flavour: Type[TFlavour] = tuple, **kwargs) -> tuple[TFlavour]:
100
+ def read_sql[TFlavour](self, cnx: MySQLConnection, query: str, flavour: Type[TFlavour] = tuple, **kwargs) -> tuple[TFlavour]:
116
101
  """
117
102
  Return tuple of tuples by default.
118
103
 
@@ -122,7 +107,7 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
122
107
  - flavour: Type[TFlavour]: Useful to return tuple of any Iterable type as dict,set,list...
123
108
  """
124
109
 
125
- with self._connection.cursor(buffered=True) as cursor:
110
+ with cnx.cursor(buffered=True) as cursor:
126
111
  cursor.execute(query)
127
112
  values: list[tuple] = cursor.fetchall()
128
113
  columns: tuple[str] = cursor.column_names
@@ -130,7 +115,7 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
130
115
 
131
116
  # FIXME [ ]: this method does not comply with the implemented interface
132
117
  @get_connection
133
- def create_tables_code_first(self, path: str | Path) -> None:
118
+ def create_tables_code_first(self, cnx: MySQLConnection, path: str | Path) -> None:
134
119
  if not isinstance(path, Path | str):
135
120
  raise ValueError
136
121
 
@@ -145,33 +130,33 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
145
130
  queries_list: list[str] = module_tree.get_queries()
146
131
 
147
132
  for query in queries_list:
148
- with self._connection.cursor(buffered=True) as cursor:
133
+ with cnx.cursor(buffered=True) as cursor:
149
134
  cursor.execute(query)
150
- self._connection.commit()
135
+ cnx.commit()
151
136
  return None
152
137
 
153
138
  @override
154
139
  @get_connection
155
- def executemany_with_values(self, query: str, values) -> None:
156
- with self._connection.cursor(buffered=True) as cursor:
140
+ def executemany_with_values(self, cnx: MySQLConnection, query: str, values) -> None:
141
+ with cnx.cursor(buffered=True) as cursor:
157
142
  cursor.executemany(query, values)
158
- self._connection.commit()
143
+ cnx.commit()
159
144
  return None
160
145
 
161
146
  @override
162
147
  @get_connection
163
- def execute_with_values(self, query: str, values) -> None:
164
- with self._connection.cursor(buffered=True) as cursor:
148
+ def execute_with_values(self, cnx: MySQLConnection, query: str, values) -> None:
149
+ with cnx.cursor(buffered=True) as cursor:
165
150
  cursor.execute(query, values)
166
- self._connection.commit()
151
+ cnx.commit()
167
152
  return None
168
153
 
169
154
  @override
170
155
  @get_connection
171
- def execute(self, query: str) -> None:
172
- with self._connection.cursor(buffered=True) as cursor:
156
+ def execute(self, cnx: MySQLConnection, query: str) -> None:
157
+ with cnx.cursor(buffered=True) as cursor:
173
158
  cursor.execute(query)
174
- self._connection.commit()
159
+ cnx.commit()
175
160
  return None
176
161
 
177
162
  @override
@@ -180,9 +165,9 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
180
165
 
181
166
  @override
182
167
  @get_connection
183
- def database_exists(self, name: str) -> bool:
168
+ def database_exists(self, cnx: MySQLConnection, name: str) -> bool:
184
169
  query = "SHOW DATABASES LIKE %s;"
185
- with self._connection.cursor(buffered=True) as cursor:
170
+ with cnx.cursor(buffered=True) as cursor:
186
171
  cursor.execute(query, (name,))
187
172
  res = cursor.fetchmany(1)
188
173
  return len(res) > 0
@@ -193,12 +178,12 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
193
178
 
194
179
  @override
195
180
  @get_connection
196
- def table_exists(self, name: str) -> bool:
197
- if not self._connection.database:
181
+ def table_exists(self, cnx: MySQLConnection, name: str) -> bool:
182
+ if not cnx.database:
198
183
  raise Exception("No database selected")
199
184
 
200
185
  query = "SHOW TABLES LIKE %s;"
201
- with self._connection.cursor(buffered=True) as cursor:
186
+ with cnx.cursor(buffered=True) as cursor:
202
187
  cursor.execute(query, (name,))
203
188
  res = cursor.fetchmany(1)
204
189
  return len(res) > 0
@@ -219,4 +204,4 @@ class MySQLRepository(IRepositoryBase[MySQLConnection]):
219
204
  @database.setter
220
205
  def database(self, value: str) -> None:
221
206
  self._data_config["database"] = value
222
- self._pool = self.__create_MySQLConnectionPool()
207
+ 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.1
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