ormlambda 3.11.2__py3-none-any.whl → 3.12.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ormlambda/__init__.py +1 -1
 - ormlambda/common/abstract_classes/clause_info_converter.py +73 -0
 - ormlambda/common/abstract_classes/decomposition_query.py +12 -68
 - ormlambda/common/abstract_classes/non_query_base.py +2 -2
 - ormlambda/common/interfaces/ICustomAlias.py +1 -1
 - ormlambda/components/delete/abstract_delete.py +2 -2
 - ormlambda/components/join/__init__.py +1 -0
 - ormlambda/databases/my_sql/clauses/drop_table.py +8 -5
 - ormlambda/databases/my_sql/clauses/group_by.py +1 -2
 - ormlambda/databases/my_sql/clauses/select.py +2 -0
 - ormlambda/databases/my_sql/clauses/upsert.py +8 -4
 - ormlambda/databases/my_sql/query_builder.py +158 -0
 - ormlambda/databases/my_sql/statements.py +18 -156
 - ormlambda/engine/url.py +4 -1
 - ormlambda/sql/clause_info/__init__.py +2 -1
 - ormlambda/sql/clause_info/aggregate_function_base.py +86 -0
 - ormlambda/sql/clause_info/clause_info.py +1 -98
 - ormlambda/sql/clause_info/interface/IClauseInfo.py +37 -0
 - ormlambda/sql/clause_info/interface/__init__.py +1 -0
 - ormlambda/sql/column.py +3 -0
 - ormlambda/statements/base_statement.py +6 -2
 - ormlambda/statements/interfaces/IStatements.py +21 -18
 - ormlambda/utils/module_tree/dynamic_module.py +3 -2
 - {ormlambda-3.11.2.dist-info → ormlambda-3.12.2.dist-info}/METADATA +56 -10
 - {ormlambda-3.11.2.dist-info → ormlambda-3.12.2.dist-info}/RECORD +28 -23
 - /ormlambda/{databases/my_sql → components/join}/join_context.py +0 -0
 - {ormlambda-3.11.2.dist-info → ormlambda-3.12.2.dist-info}/LICENSE +0 -0
 - {ormlambda-3.11.2.dist-info → ormlambda-3.12.2.dist-info}/WHEEL +0 -0
 
| 
         @@ -1,12 +1,9 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from __future__ import annotations
         
     | 
| 
       2 
     | 
    
         
            -
            from typing import Concatenate, Iterable,  
     | 
| 
      
 2 
     | 
    
         
            +
            from typing import Concatenate, Iterable, override, Type, TYPE_CHECKING, Any, Callable, Optional
         
     | 
| 
       3 
3 
     | 
    
         
             
            from mysql.connector import errors, errorcode
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            from ormlambda.sql.clause_info.clause_info_context import ClauseInfoContext
         
     | 
| 
       6 
     | 
    
         
            -
            from ormlambda.databases.my_sql.clauses.joins import JoinSelector
         
     | 
| 
       7 
5 
     | 
    
         
             
            from ormlambda import ForeignKey
         
     | 
| 
       8 
6 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            from ormlambda.common.interfaces import IQuery
         
     | 
| 
       10 
7 
     | 
    
         
             
            from mysql.connector import MySQLConnection
         
     | 
| 
       11 
8 
     | 
    
         | 
| 
       12 
9 
     | 
    
         | 
| 
         @@ -16,9 +13,9 @@ if TYPE_CHECKING: 
     | 
|
| 
       16 
13 
     | 
    
         
             
                from ormlambda.statements.types import OrderTypes
         
     | 
| 
       17 
14 
     | 
    
         
             
                from ormlambda.sql.types import ColumnType
         
     | 
| 
       18 
15 
     | 
    
         
             
                from ormlambda.statements.types import SelectCols
         
     | 
| 
       19 
     | 
    
         
            -
                from ormlambda.repository 
     | 
| 
      
 16 
     | 
    
         
            +
                from ormlambda.repository import BaseRepository
         
     | 
| 
       20 
17 
     | 
    
         
             
                from ormlambda.statements.interfaces import IStatements_two_generic
         
     | 
| 
       21 
     | 
    
         
            -
                from ormlambda. 
     | 
| 
      
 18 
     | 
    
         
            +
                from ormlambda.statements.types import TypeExists
         
     | 
| 
       22 
19 
     | 
    
         
             
                from ormlambda.sql.clause_info import IAggregate
         
     | 
| 
       23 
20 
     | 
    
         
             
                from ormlambda.statements.types import WhereTypes
         
     | 
| 
       24 
21 
     | 
    
         | 
| 
         @@ -44,8 +41,10 @@ from .clauses import Alias 
     | 
|
| 
       44 
41 
     | 
    
         
             
            from ormlambda import Table, Column
         
     | 
| 
       45 
42 
     | 
    
         
             
            from ormlambda.common.enums import JoinType
         
     | 
| 
       46 
43 
     | 
    
         
             
            from . import functions as func
         
     | 
| 
       47 
     | 
    
         
            -
            from . 
     | 
| 
      
 44 
     | 
    
         
            +
            from ormlambda.components.join import JoinContext, TupleJoinType
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
       48 
46 
     | 
    
         
             
            from ormlambda.common.global_checker import GlobalChecker
         
     | 
| 
      
 47 
     | 
    
         
            +
            from .query_builder import QueryBuilder
         
     | 
| 
       49 
48 
     | 
    
         | 
| 
       50 
49 
     | 
    
         | 
| 
       51 
50 
     | 
    
         
             
            # COMMENT: It's so important to prevent information generated by other tests from being retained in the class.
         
     | 
| 
         @@ -63,152 +62,11 @@ def clear_list[T, **P](f: Callable[Concatenate[MySQLStatements, P], T]) -> Calla 
     | 
|
| 
       63 
62 
     | 
    
         
             
                return wrapper
         
     | 
| 
       64 
63 
     | 
    
         | 
| 
       65 
64 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
            class OrderType(TypedDict):
         
     | 
| 
       67 
     | 
    
         
            -
                Select: Select
         
     | 
| 
       68 
     | 
    
         
            -
                JoinSelector: JoinSelector
         
     | 
| 
       69 
     | 
    
         
            -
                Where: Where
         
     | 
| 
       70 
     | 
    
         
            -
                Order: Order
         
     | 
| 
       71 
     | 
    
         
            -
                GroupBy: GroupBy
         
     | 
| 
       72 
     | 
    
         
            -
                Having: Having
         
     | 
| 
       73 
     | 
    
         
            -
                Limit: Limit
         
     | 
| 
       74 
     | 
    
         
            -
                Offset: Offset
         
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
            class QueryBuilder(IQuery):
         
     | 
| 
       78 
     | 
    
         
            -
                __order__: tuple[str, ...] = ("Select", "JoinSelector", "Where", "GroupBy", "Having", "Order", "Limit", "Offset")
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
     | 
    
         
            -
                def __init__(self, by: JoinType = JoinType.INNER_JOIN):
         
     | 
| 
       81 
     | 
    
         
            -
                    self._context = ClauseInfoContext()
         
     | 
| 
       82 
     | 
    
         
            -
                    self._query_list: OrderType = {}
         
     | 
| 
       83 
     | 
    
         
            -
                    self._by = by
         
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
                    self._joins: Optional[IQuery] = None
         
     | 
| 
       86 
     | 
    
         
            -
                    self._select: Optional[IQuery] = None
         
     | 
| 
       87 
     | 
    
         
            -
                    self._where: Optional[IQuery] = None
         
     | 
| 
       88 
     | 
    
         
            -
                    self._order: Optional[IQuery] = None
         
     | 
| 
       89 
     | 
    
         
            -
                    self._group_by: Optional[IQuery] = None
         
     | 
| 
       90 
     | 
    
         
            -
                    self._limit: Optional[IQuery] = None
         
     | 
| 
       91 
     | 
    
         
            -
                    self._offset: Optional[IQuery] = None
         
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
                def add_statement[T](self, clause: ClauseInfo[T]):
         
     | 
| 
       94 
     | 
    
         
            -
                    self.update_context(clause)
         
     | 
| 
       95 
     | 
    
         
            -
                    self._query_list[type(clause).__name__] = clause
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
                @property
         
     | 
| 
       98 
     | 
    
         
            -
                def by(self) -> JoinType:
         
     | 
| 
       99 
     | 
    
         
            -
                    return self._by
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
                @by.setter
         
     | 
| 
       102 
     | 
    
         
            -
                def by(self, value: JoinType) -> None:
         
     | 
| 
       103 
     | 
    
         
            -
                    self._by = value
         
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
                @property
         
     | 
| 
       106 
     | 
    
         
            -
                def JOINS(self) -> Optional[set[JoinSelector]]:
         
     | 
| 
       107 
     | 
    
         
            -
                    return self._joins
         
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
                @property
         
     | 
| 
       110 
     | 
    
         
            -
                def SELECT(self) -> IQuery:
         
     | 
| 
       111 
     | 
    
         
            -
                    return self._query_list.get("Select", None)
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
                @property
         
     | 
| 
       114 
     | 
    
         
            -
                def WHERE(self) -> IQuery:
         
     | 
| 
       115 
     | 
    
         
            -
                    where = self._query_list.get("Where", None)
         
     | 
| 
       116 
     | 
    
         
            -
                    if not isinstance(where, Iterable):
         
     | 
| 
       117 
     | 
    
         
            -
                        if not where:
         
     | 
| 
       118 
     | 
    
         
            -
                            return ()
         
     | 
| 
       119 
     | 
    
         
            -
                        return (where,)
         
     | 
| 
       120 
     | 
    
         
            -
                    return where
         
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
     | 
    
         
            -
                @property
         
     | 
| 
       123 
     | 
    
         
            -
                def ORDER(self) -> IQuery:
         
     | 
| 
       124 
     | 
    
         
            -
                    return self._query_list.get("Order", None)
         
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
                @property
         
     | 
| 
       127 
     | 
    
         
            -
                def GROUP_BY(self) -> IQuery:
         
     | 
| 
       128 
     | 
    
         
            -
                    return self._query_list.get("GroupBy", None)
         
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
                @property
         
     | 
| 
       131 
     | 
    
         
            -
                def HAVING(self) -> IQuery:
         
     | 
| 
       132 
     | 
    
         
            -
                    where = self._query_list.get("Having", None)
         
     | 
| 
       133 
     | 
    
         
            -
                    if not isinstance(where, Iterable):
         
     | 
| 
       134 
     | 
    
         
            -
                        if not where:
         
     | 
| 
       135 
     | 
    
         
            -
                            return ()
         
     | 
| 
       136 
     | 
    
         
            -
                        return (where,)
         
     | 
| 
       137 
     | 
    
         
            -
                    return where
         
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
                @property
         
     | 
| 
       140 
     | 
    
         
            -
                def LIMIT(self) -> IQuery:
         
     | 
| 
       141 
     | 
    
         
            -
                    return self._query_list.get("Limit", None)
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
                @property
         
     | 
| 
       144 
     | 
    
         
            -
                def OFFSET(self) -> IQuery:
         
     | 
| 
       145 
     | 
    
         
            -
                    return self._query_list.get("Offset", None)
         
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
                @property
         
     | 
| 
       148 
     | 
    
         
            -
                def query(self) -> str:
         
     | 
| 
       149 
     | 
    
         
            -
                    # COMMENT: (select.query, query)We must first create an alias for 'FROM' and then define all the remaining clauses.
         
     | 
| 
       150 
     | 
    
         
            -
                    # This order is mandatory because it adds the clause name to the context when accessing the .query property of 'FROM'
         
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
       152 
     | 
    
         
            -
                    extract_joins = self.pop_tables_and_create_joins_from_ForeignKey(self._by)
         
     | 
| 
       153 
     | 
    
         
            -
             
     | 
| 
       154 
     | 
    
         
            -
                    JOINS = self.stringify_foreign_key(extract_joins, " ")
         
     | 
| 
       155 
     | 
    
         
            -
                    query_list: tuple[str, ...] = (
         
     | 
| 
       156 
     | 
    
         
            -
                        self.SELECT.query,
         
     | 
| 
       157 
     | 
    
         
            -
                        JOINS,
         
     | 
| 
       158 
     | 
    
         
            -
                        Where.join_condition(self.WHERE, True, self._context) if self.WHERE else None,
         
     | 
| 
       159 
     | 
    
         
            -
                        self.GROUP_BY.query if self.GROUP_BY else None,
         
     | 
| 
       160 
     | 
    
         
            -
                        Having.join_condition(self.HAVING, True, self._context) if self.HAVING else None,
         
     | 
| 
       161 
     | 
    
         
            -
                        self.ORDER.query if self.ORDER else None,
         
     | 
| 
       162 
     | 
    
         
            -
                        self.LIMIT.query if self.LIMIT else None,
         
     | 
| 
       163 
     | 
    
         
            -
                        self.OFFSET.query if self.OFFSET else None,
         
     | 
| 
       164 
     | 
    
         
            -
                    )
         
     | 
| 
       165 
     | 
    
         
            -
                    return " ".join([x for x in query_list if x])
         
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
       167 
     | 
    
         
            -
                def stringify_foreign_key(self, joins: set[JoinSelector], sep: str = "\n") -> Optional[str]:
         
     | 
| 
       168 
     | 
    
         
            -
                    if not joins:
         
     | 
| 
       169 
     | 
    
         
            -
                        return None
         
     | 
| 
       170 
     | 
    
         
            -
                    sorted_joins = JoinSelector.sort_join_selectors(joins)
         
     | 
| 
       171 
     | 
    
         
            -
                    return f"{sep}".join([join.query for join in sorted_joins])
         
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
                def pop_tables_and_create_joins_from_ForeignKey(self, by: JoinType = JoinType.INNER_JOIN) -> set[JoinSelector]:
         
     | 
| 
       174 
     | 
    
         
            -
                    # 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.
         
     | 
| 
       175 
     | 
    
         
            -
                    if not ForeignKey.stored_calls:
         
     | 
| 
       176 
     | 
    
         
            -
                        return None
         
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
                    joins = set()
         
     | 
| 
       179 
     | 
    
         
            -
                    # Always it's gonna be a set of two
         
     | 
| 
       180 
     | 
    
         
            -
                    # FIXME [x]: Resolved when we get Compare object instead ClauseInfo. For instance, when we have multiples condition using '&' or '|'
         
     | 
| 
       181 
     | 
    
         
            -
                    for fk in ForeignKey.stored_calls.copy():
         
     | 
| 
       182 
     | 
    
         
            -
                        fk = ForeignKey.stored_calls.pop(fk)
         
     | 
| 
       183 
     | 
    
         
            -
                        self._context._add_table_alias(fk.tright, fk.alias)
         
     | 
| 
       184 
     | 
    
         
            -
                        join = JoinSelector(fk.resolved_function(self._context), by, context=self._context, alias=fk.alias)
         
     | 
| 
       185 
     | 
    
         
            -
                        joins.add(join)
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
                    return joins
         
     | 
| 
       188 
     | 
    
         
            -
             
     | 
| 
       189 
     | 
    
         
            -
                def clear(self) -> None:
         
     | 
| 
       190 
     | 
    
         
            -
                    self.__init__()
         
     | 
| 
       191 
     | 
    
         
            -
                    return None
         
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
       193 
     | 
    
         
            -
                def update_context(self, clause: ClauseInfo) -> None:
         
     | 
| 
       194 
     | 
    
         
            -
                    if not hasattr(clause, "context"):
         
     | 
| 
       195 
     | 
    
         
            -
                        return None
         
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
       197 
     | 
    
         
            -
                    if clause.context is not None:
         
     | 
| 
       198 
     | 
    
         
            -
                        self._context.update(clause.context)
         
     | 
| 
       199 
     | 
    
         
            -
                    clause.context = self._context
         
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
       202 
65 
     | 
    
         
             
            class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]):
         
     | 
| 
       203 
     | 
    
         
            -
                def __init__(self, model: tuple[T, *Ts], repository:  
     | 
| 
      
 66 
     | 
    
         
            +
                def __init__(self, model: tuple[T, *Ts], repository: BaseRepository) -> None:
         
     | 
| 
       204 
67 
     | 
    
         
             
                    super().__init__(model, repository=repository)
         
     | 
| 
       205 
68 
     | 
    
         
             
                    self._query_builder = QueryBuilder()
         
     | 
| 
       206 
69 
     | 
    
         | 
| 
       207 
     | 
    
         
            -
                @property
         
     | 
| 
       208 
     | 
    
         
            -
                @override
         
     | 
| 
       209 
     | 
    
         
            -
                def repository(self) -> IRepositoryBase:
         
     | 
| 
       210 
     | 
    
         
            -
                    return self._repository
         
     | 
| 
       211 
     | 
    
         
            -
             
     | 
| 
       212 
70 
     | 
    
         
             
                @override
         
     | 
| 
       213 
71 
     | 
    
         
             
                def create_table(self, if_exists: TypeExists = "fail") -> None:
         
     | 
| 
       214 
72 
     | 
    
         
             
                    name: str = self._model.__table_name__
         
     | 
| 
         @@ -232,10 +90,6 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]): 
     | 
|
| 
       232 
90 
     | 
    
         
             
                    self._repository.execute(query)
         
     | 
| 
       233 
91 
     | 
    
         
             
                    return None
         
     | 
| 
       234 
92 
     | 
    
         | 
| 
       235 
     | 
    
         
            -
                @override
         
     | 
| 
       236 
     | 
    
         
            -
                def table_exists(self) -> bool:
         
     | 
| 
       237 
     | 
    
         
            -
                    return self._repository.table_exists(self._model.__table_name__)
         
     | 
| 
       238 
     | 
    
         
            -
             
     | 
| 
       239 
93 
     | 
    
         
             
                @override
         
     | 
| 
       240 
94 
     | 
    
         
             
                @clear_list
         
     | 
| 
       241 
95 
     | 
    
         
             
                def insert(self, instances: T | list[T]) -> None:
         
     | 
| 
         @@ -293,7 +147,7 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]): 
     | 
|
| 
       293 
147 
     | 
    
         
             
                @override
         
     | 
| 
       294 
148 
     | 
    
         
             
                def count[TProp](
         
     | 
| 
       295 
149 
     | 
    
         
             
                    self,
         
     | 
| 
       296 
     | 
    
         
            -
                    selection: None | SelectCols[T,TProp] = lambda x: "*",
         
     | 
| 
      
 150 
     | 
    
         
            +
                    selection: None | SelectCols[T, TProp] = lambda x: "*",
         
     | 
| 
       297 
151 
     | 
    
         
             
                    alias="count",
         
     | 
| 
       298 
152 
     | 
    
         
             
                    execute: bool = False,
         
     | 
| 
       299 
153 
     | 
    
         
             
                ) -> Optional[int]:
         
     | 
| 
         @@ -386,6 +240,9 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]): 
     | 
|
| 
       386 
240 
     | 
    
         
             
                    by: JoinType = JoinType.INNER_JOIN,
         
     | 
| 
       387 
241 
     | 
    
         
             
                    **kwargs,
         
     | 
| 
       388 
242 
     | 
    
         
             
                ):
         
     | 
| 
      
 243 
     | 
    
         
            +
                    if "alias" in kwargs:
         
     | 
| 
      
 244 
     | 
    
         
            +
                        alias = kwargs.pop("alias")
         
     | 
| 
      
 245 
     | 
    
         
            +
                        kwargs["alias_clause"] = alias
         
     | 
| 
       389 
246 
     | 
    
         
             
                    select_clause = GlobalChecker.resolved_callback_object(selector, self._models)
         
     | 
| 
       390 
247 
     | 
    
         | 
| 
       391 
248 
     | 
    
         
             
                    if selector is None:
         
     | 
| 
         @@ -400,6 +257,7 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]): 
     | 
|
| 
       400 
257 
     | 
    
         
             
                    select = Select[T, *Ts](
         
     | 
| 
       401 
258 
     | 
    
         
             
                        self._models,
         
     | 
| 
       402 
259 
     | 
    
         
             
                        columns=select_clause,
         
     | 
| 
      
 260 
     | 
    
         
            +
                        **kwargs,
         
     | 
| 
       403 
261 
     | 
    
         
             
                    )
         
     | 
| 
       404 
262 
     | 
    
         
             
                    self._query_builder.add_statement(select)
         
     | 
| 
       405 
263 
     | 
    
         | 
| 
         @@ -458,14 +316,18 @@ class MySQLStatements[T: Table, *Ts](BaseStatement[T, MySQLConnection]): 
     | 
|
| 
       458 
316 
     | 
    
         
             
                    )
         
     | 
| 
       459 
317 
     | 
    
         | 
| 
       460 
318 
     | 
    
         
             
                @override
         
     | 
| 
       461 
     | 
    
         
            -
                def groupby[TProp](self, column: ColumnType[TProp] | Callable[[T, *Ts], Any]):
         
     | 
| 
      
 319 
     | 
    
         
            +
                def groupby[TProp](self, column: ColumnType[TProp] | Callable[[T, *Ts], Any]) -> IStatements_two_generic[T]:
         
     | 
| 
      
 320 
     | 
    
         
            +
                    column = GlobalChecker.resolved_callback_object(column, self.models)
         
     | 
| 
      
 321 
     | 
    
         
            +
             
     | 
| 
       462 
322 
     | 
    
         
             
                    groupby = GroupBy(column=column, context=self._query_builder._context)
         
     | 
| 
       463 
323 
     | 
    
         
             
                    # Only can be one LIMIT SQL parameter. We only use the last LimitQuery
         
     | 
| 
       464 
324 
     | 
    
         
             
                    self._query_builder.add_statement(groupby)
         
     | 
| 
       465 
325 
     | 
    
         
             
                    return self
         
     | 
| 
       466 
326 
     | 
    
         | 
| 
       467 
327 
     | 
    
         
             
                @override
         
     | 
| 
       468 
     | 
    
         
            -
                def alias[TProp](self, column:  
     | 
| 
      
 328 
     | 
    
         
            +
                def alias[TProp](self, column: SelectCols[T, TProp], alias: AliasType[ClauseInfo[T]]) -> ClauseInfo[T]:
         
     | 
| 
      
 329 
     | 
    
         
            +
                    column = GlobalChecker.resolved_callback_object(column, self.models)
         
     | 
| 
      
 330 
     | 
    
         
            +
             
     | 
| 
       469 
331 
     | 
    
         
             
                    return Alias(
         
     | 
| 
       470 
332 
     | 
    
         
             
                        table=column.table,
         
     | 
| 
       471 
333 
     | 
    
         
             
                        column=column,
         
     | 
    
        ormlambda/engine/url.py
    CHANGED
    
    | 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            """
         
     | 
| 
       2 
2 
     | 
    
         
             
            URL class extracted from SQLAlchemy
         
     | 
| 
       3 
3 
     | 
    
         
             
            """
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       4 
5 
     | 
    
         
             
            from __future__ import annotations
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
7 
     | 
    
         
             
            import re
         
     | 
| 
         @@ -27,7 +28,9 @@ from urllib.parse import ( 
     | 
|
| 
       27 
28 
     | 
    
         | 
| 
       28 
29 
     | 
    
         
             
            from . import utils
         
     | 
| 
       29 
30 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
            type DrivernameType = Literal[ 
     | 
| 
      
 31 
     | 
    
         
            +
            type DrivernameType = Literal["mysql"] | str
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
       31 
34 
     | 
    
         
             
            class URL(NamedTuple):
         
     | 
| 
       32 
35 
     | 
    
         
             
                """
         
     | 
| 
       33 
36 
     | 
    
         
             
                Represent the components of a URL used to connect to a database.
         
     | 
| 
         @@ -1,3 +1,4 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from .interface import IAggregate  # noqa: F401
         
     | 
| 
       2 
     | 
    
         
            -
            from .clause_info import ClauseInfo 
     | 
| 
      
 2 
     | 
    
         
            +
            from .clause_info import ClauseInfo  # noqa: F401
         
     | 
| 
      
 3 
     | 
    
         
            +
            from .aggregate_function_base import AggregateFunctionBase  # noqa: F401
         
     | 
| 
       3 
4 
     | 
    
         
             
            from .clause_info_context import ClauseContextType, ClauseInfoContext  # noqa: F401
         
     | 
| 
         @@ -0,0 +1,86 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            from __future__ import annotations
         
     | 
| 
      
 2 
     | 
    
         
            +
            import abc
         
     | 
| 
      
 3 
     | 
    
         
            +
            import typing as tp
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            from ormlambda import Table
         
     | 
| 
      
 6 
     | 
    
         
            +
            from ormlambda import Column
         
     | 
| 
      
 7 
     | 
    
         
            +
            from ormlambda.sql.types import (
         
     | 
| 
      
 8 
     | 
    
         
            +
                TableType,
         
     | 
| 
      
 9 
     | 
    
         
            +
                ColumnType,
         
     | 
| 
      
 10 
     | 
    
         
            +
                AliasType,
         
     | 
| 
      
 11 
     | 
    
         
            +
            )
         
     | 
| 
      
 12 
     | 
    
         
            +
            from .interface import IAggregate
         
     | 
| 
      
 13 
     | 
    
         
            +
            from ormlambda.common.errors import NotKeysInIAggregateError
         
     | 
| 
      
 14 
     | 
    
         
            +
            from ormlambda.sql import ForeignKey
         
     | 
| 
      
 15 
     | 
    
         
            +
            from ormlambda.sql.table import TableMeta
         
     | 
| 
      
 16 
     | 
    
         
            +
            from .clause_info import ClauseInfo
         
     | 
| 
      
 17 
     | 
    
         
            +
            from .clause_info_context import ClauseContextType
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
         
     | 
| 
      
 21 
     | 
    
         
            +
                def __init__[TProp: Column](
         
     | 
| 
      
 22 
     | 
    
         
            +
                    self,
         
     | 
| 
      
 23 
     | 
    
         
            +
                    table: TableType[T],
         
     | 
| 
      
 24 
     | 
    
         
            +
                    column: tp.Optional[ColumnType[TProp]] = None,
         
     | 
| 
      
 25 
     | 
    
         
            +
                    alias_table: tp.Optional[AliasType[ClauseInfo[T]]] = None,
         
     | 
| 
      
 26 
     | 
    
         
            +
                    alias_clause: tp.Optional[AliasType[ClauseInfo[T]]] = None,
         
     | 
| 
      
 27 
     | 
    
         
            +
                    context: ClauseContextType = None,
         
     | 
| 
      
 28 
     | 
    
         
            +
                    keep_asterisk: bool = False,
         
     | 
| 
      
 29 
     | 
    
         
            +
                    preserve_context: bool = False,
         
     | 
| 
      
 30 
     | 
    
         
            +
                ):
         
     | 
| 
      
 31 
     | 
    
         
            +
                    self._alias_aggregate = alias_clause
         
     | 
| 
      
 32 
     | 
    
         
            +
                    super().__init__(
         
     | 
| 
      
 33 
     | 
    
         
            +
                        table=table,
         
     | 
| 
      
 34 
     | 
    
         
            +
                        column=column,
         
     | 
| 
      
 35 
     | 
    
         
            +
                        alias_table=alias_table,
         
     | 
| 
      
 36 
     | 
    
         
            +
                        context=context,
         
     | 
| 
      
 37 
     | 
    
         
            +
                        keep_asterisk=keep_asterisk,
         
     | 
| 
      
 38 
     | 
    
         
            +
                        preserve_context=preserve_context,
         
     | 
| 
      
 39 
     | 
    
         
            +
                    )
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 42 
     | 
    
         
            +
                @abc.abstractmethod
         
     | 
| 
      
 43 
     | 
    
         
            +
                def FUNCTION_NAME() -> str: ...
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 46 
     | 
    
         
            +
                def _convert_into_clauseInfo[TypeColumns, TProp](cls, columns: ClauseInfo | ColumnType[TProp], context: ClauseContextType) -> list[ClauseInfo]:
         
     | 
| 
      
 47 
     | 
    
         
            +
                    type DEFAULT = tp.Literal["default"]
         
     | 
| 
      
 48 
     | 
    
         
            +
                    type ClusterType = ColumnType | ForeignKey | DEFAULT
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    dicc_type: dict[ClusterType, tp.Callable[[ClusterType], ClauseInfo]] = {
         
     | 
| 
      
 51 
     | 
    
         
            +
                        Column: lambda column: ClauseInfo(column.table, column, context=context),
         
     | 
| 
      
 52 
     | 
    
         
            +
                        ClauseInfo: lambda column: column,
         
     | 
| 
      
 53 
     | 
    
         
            +
                        ForeignKey: lambda tbl: ClauseInfo(tbl.tright, tbl.tright, context=context),
         
     | 
| 
      
 54 
     | 
    
         
            +
                        TableMeta: lambda tbl: ClauseInfo(tbl, tbl, context=context),
         
     | 
| 
      
 55 
     | 
    
         
            +
                        "default": lambda column: ClauseInfo(table=None, column=column, context=context),
         
     | 
| 
      
 56 
     | 
    
         
            +
                    }
         
     | 
| 
      
 57 
     | 
    
         
            +
                    all_clauses: list[ClauseInfo] = []
         
     | 
| 
      
 58 
     | 
    
         
            +
                    if isinstance(columns, str) or not isinstance(columns, tp.Iterable):
         
     | 
| 
      
 59 
     | 
    
         
            +
                        columns = (columns,)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    for value in columns:
         
     | 
| 
      
 61 
     | 
    
         
            +
                        all_clauses.append(dicc_type.get(type(value), dicc_type["default"])(value))
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                    return all_clauses
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                @tp.override
         
     | 
| 
      
 66 
     | 
    
         
            +
                @property
         
     | 
| 
      
 67 
     | 
    
         
            +
                def query(self) -> str:
         
     | 
| 
      
 68 
     | 
    
         
            +
                    wrapped_ci = self.wrapped_clause_info(self)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    if not self._alias_aggregate:
         
     | 
| 
      
 70 
     | 
    
         
            +
                        return wrapped_ci
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    return ClauseInfo(
         
     | 
| 
      
 73 
     | 
    
         
            +
                        table=None,
         
     | 
| 
      
 74 
     | 
    
         
            +
                        column=wrapped_ci,
         
     | 
| 
      
 75 
     | 
    
         
            +
                        alias_clause=self._alias_aggregate,
         
     | 
| 
      
 76 
     | 
    
         
            +
                        context=self._context,
         
     | 
| 
      
 77 
     | 
    
         
            +
                        keep_asterisk=self._keep_asterisk,
         
     | 
| 
      
 78 
     | 
    
         
            +
                        preserve_context=self._preserve_context,
         
     | 
| 
      
 79 
     | 
    
         
            +
                    ).query
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def wrapped_clause_info(self, ci: ClauseInfo[T]) -> str:
         
     | 
| 
      
 82 
     | 
    
         
            +
                    # avoid use placeholder when using IAggregate because no make sense.
         
     | 
| 
      
 83 
     | 
    
         
            +
                    if self._alias_aggregate and (found := self._keyRegex.findall(self._alias_aggregate)):
         
     | 
| 
      
 84 
     | 
    
         
            +
                        raise NotKeysInIAggregateError(found)
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                    return f"{self.FUNCTION_NAME()}({ci._create_query()})"
         
     | 
| 
         @@ -1,21 +1,17 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from __future__ import annotations
         
     | 
| 
       2 
     | 
    
         
            -
            import abc
         
     | 
| 
       3 
2 
     | 
    
         
             
            import typing as tp
         
     | 
| 
       4 
3 
     | 
    
         
             
            import re
         
     | 
| 
       5 
4 
     | 
    
         | 
| 
       6 
5 
     | 
    
         
             
            from ormlambda import Table
         
     | 
| 
       7 
6 
     | 
    
         
             
            from ormlambda import Column
         
     | 
| 
       8 
     | 
    
         
            -
            from ormlambda.common.interfaces.IQueryCommand import IQuery
         
     | 
| 
       9 
7 
     | 
    
         
             
            from ormlambda.sql.types import (
         
     | 
| 
       10 
8 
     | 
    
         
             
                ASTERISK,
         
     | 
| 
       11 
9 
     | 
    
         
             
                TableType,
         
     | 
| 
       12 
10 
     | 
    
         
             
                ColumnType,
         
     | 
| 
       13 
11 
     | 
    
         
             
                AliasType,
         
     | 
| 
       14 
12 
     | 
    
         
             
            )
         
     | 
| 
       15 
     | 
    
         
            -
            from .interface import  
     | 
| 
       16 
     | 
    
         
            -
            from ormlambda.common.errors import NotKeysInIAggregateError
         
     | 
| 
      
 13 
     | 
    
         
            +
            from .interface import IClauseInfo
         
     | 
| 
       17 
14 
     | 
    
         
             
            from ormlambda.sql import ForeignKey
         
     | 
| 
       18 
     | 
    
         
            -
            from ormlambda.sql.table import TableMeta
         
     | 
| 
       19 
15 
     | 
    
         
             
            from ormlambda.caster import Caster
         
     | 
| 
       20 
16 
     | 
    
         | 
| 
       21 
17 
     | 
    
         | 
| 
         @@ -32,30 +28,6 @@ class ReplacePlaceholderError(ValueError): 
     | 
|
| 
       32 
28 
     | 
    
         
             
                    return "You cannot use {" + self.placeholder + "} placeholder without using '" + self.attr + "' attribute"
         
     | 
| 
       33 
29 
     | 
    
         | 
| 
       34 
30 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
            class IClauseInfo[T: Table](IQuery):
         
     | 
| 
       36 
     | 
    
         
            -
                @property
         
     | 
| 
       37 
     | 
    
         
            -
                @abc.abstractmethod
         
     | 
| 
       38 
     | 
    
         
            -
                def table(self) -> TableType[T]: ...
         
     | 
| 
       39 
     | 
    
         
            -
                @property
         
     | 
| 
       40 
     | 
    
         
            -
                @abc.abstractmethod
         
     | 
| 
       41 
     | 
    
         
            -
                def alias_clause(self) -> tp.Optional[str]: ...
         
     | 
| 
       42 
     | 
    
         
            -
                @property
         
     | 
| 
       43 
     | 
    
         
            -
                @abc.abstractmethod
         
     | 
| 
       44 
     | 
    
         
            -
                def alias_table(self) -> tp.Optional[str]: ...
         
     | 
| 
       45 
     | 
    
         
            -
                @property
         
     | 
| 
       46 
     | 
    
         
            -
                @abc.abstractmethod
         
     | 
| 
       47 
     | 
    
         
            -
                def column(self) -> str: ...
         
     | 
| 
       48 
     | 
    
         
            -
                @property
         
     | 
| 
       49 
     | 
    
         
            -
                @abc.abstractmethod
         
     | 
| 
       50 
     | 
    
         
            -
                def unresolved_column(self) -> ColumnType: ...
         
     | 
| 
       51 
     | 
    
         
            -
                @property
         
     | 
| 
       52 
     | 
    
         
            -
                @abc.abstractmethod
         
     | 
| 
       53 
     | 
    
         
            -
                def context(self) -> ClauseContextType: ...
         
     | 
| 
       54 
     | 
    
         
            -
                @property
         
     | 
| 
       55 
     | 
    
         
            -
                @abc.abstractmethod
         
     | 
| 
       56 
     | 
    
         
            -
                def dtype[TProp](self) -> tp.Optional[tp.Type[TProp]]: ...
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
31 
     | 
    
         
             
            class ClauseInfo[T: Table](IClauseInfo[T]):
         
     | 
| 
       60 
32 
     | 
    
         
             
                _keyRegex: re.Pattern = re.compile(r"{([^{}:]+)}")
         
     | 
| 
       61 
33 
     | 
    
         | 
| 
         @@ -363,72 +335,3 @@ class ClauseInfo[T: Table](IClauseInfo[T]): 
     | 
|
| 
       363 
335 
     | 
    
         
             
                    if isinstance(data, Column):
         
     | 
| 
       364 
336 
     | 
    
         
             
                        return True
         
     | 
| 
       365 
337 
     | 
    
         
             
                    return False
         
     | 
| 
       366 
     | 
    
         
            -
             
     | 
| 
       367 
     | 
    
         
            -
             
     | 
| 
       368 
     | 
    
         
            -
            class AggregateFunctionBase[T: Table](ClauseInfo[T], IAggregate):
         
     | 
| 
       369 
     | 
    
         
            -
                def __init__[TProp: Column](
         
     | 
| 
       370 
     | 
    
         
            -
                    self,
         
     | 
| 
       371 
     | 
    
         
            -
                    table: TableType[T],
         
     | 
| 
       372 
     | 
    
         
            -
                    column: tp.Optional[ColumnType[TProp]] = None,
         
     | 
| 
       373 
     | 
    
         
            -
                    alias_table: tp.Optional[AliasType[ClauseInfo[T]]] = None,
         
     | 
| 
       374 
     | 
    
         
            -
                    alias_clause: tp.Optional[AliasType[ClauseInfo[T]]] = None,
         
     | 
| 
       375 
     | 
    
         
            -
                    context: ClauseContextType = None,
         
     | 
| 
       376 
     | 
    
         
            -
                    keep_asterisk: bool = False,
         
     | 
| 
       377 
     | 
    
         
            -
                    preserve_context: bool = False,
         
     | 
| 
       378 
     | 
    
         
            -
                ):
         
     | 
| 
       379 
     | 
    
         
            -
                    self._alias_aggregate = alias_clause
         
     | 
| 
       380 
     | 
    
         
            -
                    super().__init__(
         
     | 
| 
       381 
     | 
    
         
            -
                        table=table,
         
     | 
| 
       382 
     | 
    
         
            -
                        column=column,
         
     | 
| 
       383 
     | 
    
         
            -
                        alias_table=alias_table,
         
     | 
| 
       384 
     | 
    
         
            -
                        context=context,
         
     | 
| 
       385 
     | 
    
         
            -
                        keep_asterisk=keep_asterisk,
         
     | 
| 
       386 
     | 
    
         
            -
                        preserve_context=preserve_context,
         
     | 
| 
       387 
     | 
    
         
            -
                    )
         
     | 
| 
       388 
     | 
    
         
            -
             
     | 
| 
       389 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       390 
     | 
    
         
            -
                @abc.abstractmethod
         
     | 
| 
       391 
     | 
    
         
            -
                def FUNCTION_NAME() -> str: ...
         
     | 
| 
       392 
     | 
    
         
            -
             
     | 
| 
       393 
     | 
    
         
            -
                @classmethod
         
     | 
| 
       394 
     | 
    
         
            -
                def _convert_into_clauseInfo[TypeColumns, TProp](cls, columns: ClauseInfo | ColumnType[TProp], context: ClauseContextType) -> list[ClauseInfo]:
         
     | 
| 
       395 
     | 
    
         
            -
                    type DEFAULT = tp.Literal["default"]
         
     | 
| 
       396 
     | 
    
         
            -
                    type ClusterType = ColumnType | ForeignKey | DEFAULT
         
     | 
| 
       397 
     | 
    
         
            -
             
     | 
| 
       398 
     | 
    
         
            -
                    dicc_type: dict[ClusterType, tp.Callable[[ClusterType], ClauseInfo]] = {
         
     | 
| 
       399 
     | 
    
         
            -
                        Column: lambda column: ClauseInfo(column.table, column, context=context),
         
     | 
| 
       400 
     | 
    
         
            -
                        ClauseInfo: lambda column: column,
         
     | 
| 
       401 
     | 
    
         
            -
                        ForeignKey: lambda tbl: ClauseInfo(tbl.tright, tbl.tright, context=context),
         
     | 
| 
       402 
     | 
    
         
            -
                        TableMeta: lambda tbl: ClauseInfo(tbl, tbl, context=context),
         
     | 
| 
       403 
     | 
    
         
            -
                        "default": lambda column: ClauseInfo(table=None, column=column, context=context),
         
     | 
| 
       404 
     | 
    
         
            -
                    }
         
     | 
| 
       405 
     | 
    
         
            -
                    all_clauses: list[ClauseInfo] = []
         
     | 
| 
       406 
     | 
    
         
            -
                    if isinstance(columns, str) or not isinstance(columns, tp.Iterable):
         
     | 
| 
       407 
     | 
    
         
            -
                        columns = (columns,)
         
     | 
| 
       408 
     | 
    
         
            -
                    for value in columns:
         
     | 
| 
       409 
     | 
    
         
            -
                        all_clauses.append(dicc_type.get(type(value), dicc_type["default"])(value))
         
     | 
| 
       410 
     | 
    
         
            -
             
     | 
| 
       411 
     | 
    
         
            -
                    return all_clauses
         
     | 
| 
       412 
     | 
    
         
            -
             
     | 
| 
       413 
     | 
    
         
            -
                @tp.override
         
     | 
| 
       414 
     | 
    
         
            -
                @property
         
     | 
| 
       415 
     | 
    
         
            -
                def query(self) -> str:
         
     | 
| 
       416 
     | 
    
         
            -
                    wrapped_ci = self.wrapped_clause_info(self)
         
     | 
| 
       417 
     | 
    
         
            -
                    if not self._alias_aggregate:
         
     | 
| 
       418 
     | 
    
         
            -
                        return wrapped_ci
         
     | 
| 
       419 
     | 
    
         
            -
             
     | 
| 
       420 
     | 
    
         
            -
                    return ClauseInfo(
         
     | 
| 
       421 
     | 
    
         
            -
                        table=None,
         
     | 
| 
       422 
     | 
    
         
            -
                        column=wrapped_ci,
         
     | 
| 
       423 
     | 
    
         
            -
                        alias_clause=self._alias_aggregate,
         
     | 
| 
       424 
     | 
    
         
            -
                        context=self._context,
         
     | 
| 
       425 
     | 
    
         
            -
                        keep_asterisk=self._keep_asterisk,
         
     | 
| 
       426 
     | 
    
         
            -
                        preserve_context=self._preserve_context,
         
     | 
| 
       427 
     | 
    
         
            -
                    ).query
         
     | 
| 
       428 
     | 
    
         
            -
             
     | 
| 
       429 
     | 
    
         
            -
                def wrapped_clause_info(self, ci: ClauseInfo[T]) -> str:
         
     | 
| 
       430 
     | 
    
         
            -
                    # avoid use placeholder when using IAggregate because no make sense.
         
     | 
| 
       431 
     | 
    
         
            -
                    if self._alias_aggregate and (found := self._keyRegex.findall(self._alias_aggregate)):
         
     | 
| 
       432 
     | 
    
         
            -
                        raise NotKeysInIAggregateError(found)
         
     | 
| 
       433 
     | 
    
         
            -
             
     | 
| 
       434 
     | 
    
         
            -
                    return f"{self.FUNCTION_NAME()}({ci._create_query()})"
         
     | 
| 
         @@ -0,0 +1,37 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            from __future__ import annotations
         
     | 
| 
      
 2 
     | 
    
         
            +
            import abc
         
     | 
| 
      
 3 
     | 
    
         
            +
            import typing as tp
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            from ormlambda import Table
         
     | 
| 
      
 6 
     | 
    
         
            +
            from ormlambda.common.interfaces.IQueryCommand import IQuery
         
     | 
| 
      
 7 
     | 
    
         
            +
            from ormlambda.sql.types import (
         
     | 
| 
      
 8 
     | 
    
         
            +
                TableType,
         
     | 
| 
      
 9 
     | 
    
         
            +
                ColumnType,
         
     | 
| 
      
 10 
     | 
    
         
            +
            )
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            from ..clause_info_context import ClauseContextType
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            class IClauseInfo[T: Table](IQuery):
         
     | 
| 
      
 17 
     | 
    
         
            +
                @property
         
     | 
| 
      
 18 
     | 
    
         
            +
                @abc.abstractmethod
         
     | 
| 
      
 19 
     | 
    
         
            +
                def table(self) -> TableType[T]: ...
         
     | 
| 
      
 20 
     | 
    
         
            +
                @property
         
     | 
| 
      
 21 
     | 
    
         
            +
                @abc.abstractmethod
         
     | 
| 
      
 22 
     | 
    
         
            +
                def alias_clause(self) -> tp.Optional[str]: ...
         
     | 
| 
      
 23 
     | 
    
         
            +
                @property
         
     | 
| 
      
 24 
     | 
    
         
            +
                @abc.abstractmethod
         
     | 
| 
      
 25 
     | 
    
         
            +
                def alias_table(self) -> tp.Optional[str]: ...
         
     | 
| 
      
 26 
     | 
    
         
            +
                @property
         
     | 
| 
      
 27 
     | 
    
         
            +
                @abc.abstractmethod
         
     | 
| 
      
 28 
     | 
    
         
            +
                def column(self) -> str: ...
         
     | 
| 
      
 29 
     | 
    
         
            +
                @property
         
     | 
| 
      
 30 
     | 
    
         
            +
                @abc.abstractmethod
         
     | 
| 
      
 31 
     | 
    
         
            +
                def unresolved_column(self) -> ColumnType: ...
         
     | 
| 
      
 32 
     | 
    
         
            +
                @property
         
     | 
| 
      
 33 
     | 
    
         
            +
                @abc.abstractmethod
         
     | 
| 
      
 34 
     | 
    
         
            +
                def context(self) -> ClauseContextType: ...
         
     | 
| 
      
 35 
     | 
    
         
            +
                @property
         
     | 
| 
      
 36 
     | 
    
         
            +
                @abc.abstractmethod
         
     | 
| 
      
 37 
     | 
    
         
            +
                def dtype[TProp](self) -> tp.Optional[tp.Type[TProp]]: ...
         
     | 
    
        ormlambda/sql/column.py
    CHANGED
    
    | 
         @@ -128,6 +128,9 @@ class Column[TProp]: 
     | 
|
| 
       128 
128 
     | 
    
         
             
                    return self.__comparer_creator(other, ConditionType.GREATER_THAN_OR_EQUAL.value, *args)
         
     | 
| 
       129 
129 
     | 
    
         | 
| 
       130 
130 
     | 
    
         
             
                def contains[LTable, OTherTable, OtherProp](self, other: ColumnType[OtherProp], *args) -> Comparer[LTable, TProp, OTherTable, OtherProp]:
         
     | 
| 
      
 131 
     | 
    
         
            +
                    if not isinstance(other, tuple) and isinstance(other, Iterable):
         
     | 
| 
      
 132 
     | 
    
         
            +
                        other = tuple(other)
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
       131 
134 
     | 
    
         
             
                    return self.__comparer_creator(other, ConditionType.IN.value, *args)
         
     | 
| 
       132 
135 
     | 
    
         | 
| 
       133 
136 
     | 
    
         
             
                def not_contains[LTable, OTherTable, OtherProp](self, other: ColumnType[OtherProp], *args) -> Comparer[LTable, TProp, OTherTable, OtherProp]:
         
     | 
| 
         @@ -33,6 +33,10 @@ class BaseStatement[T: Table, TRepo](IStatements_two_generic[T, TRepo]): 
     | 
|
| 
       33 
33 
     | 
    
         
             
                        # Si no heredase de Table no sabriamos identificar el tipo de dato del que se trata porque al llamar a isinstance, obtendriamos el nombre de la clase que mapea a la tabla, Encargo, Edificio, Presupuesto y no podriamos crear una clase generica
         
     | 
| 
       34 
34 
     | 
    
         
             
                        raise Exception(f"'{model}' class does not inherit from Table class")
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
      
 36 
     | 
    
         
            +
                @override
         
     | 
| 
      
 37 
     | 
    
         
            +
                def table_exists(self) -> bool:
         
     | 
| 
      
 38 
     | 
    
         
            +
                    return self._repository.table_exists(self._model.__table_name__)
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
       36 
40 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       37 
41 
     | 
    
         
             
                def __valid_repository(repository: Any) -> bool:
         
     | 
| 
       38 
42 
     | 
    
         
             
                    if not isinstance(repository, BaseRepository):
         
     | 
| 
         @@ -67,8 +71,8 @@ class BaseStatement[T: Table, TRepo](IStatements_two_generic[T, TRepo]): 
     | 
|
| 
       67 
71 
     | 
    
         
             
                    return self._models
         
     | 
| 
       68 
72 
     | 
    
         | 
| 
       69 
73 
     | 
    
         
             
                @property
         
     | 
| 
       70 
     | 
    
         
            -
                 
     | 
| 
       71 
     | 
    
         
            -
             
     | 
| 
      
 74 
     | 
    
         
            +
                def repository(self) -> BaseRepository:
         
     | 
| 
      
 75 
     | 
    
         
            +
                    return self._repository
         
     | 
| 
       72 
76 
     | 
    
         | 
| 
       73 
77 
     | 
    
         | 
| 
       74 
78 
     | 
    
         
             
            class ClusterQuery[T]:
         
     | 
| 
         @@ -4,13 +4,12 @@ from enum import Enum 
     | 
|
| 
       4 
4 
     | 
    
         
             
            from abc import abstractmethod, ABC
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
7 
     | 
    
         
             
            if TYPE_CHECKING:
         
     | 
| 
       9 
8 
     | 
    
         
             
                from ormlambda.repository import BaseRepository
         
     | 
| 
       10 
9 
     | 
    
         
             
                from ormlambda import Table
         
     | 
| 
       11 
10 
     | 
    
         
             
                from ormlambda.sql.clause_info import IAggregate
         
     | 
| 
       12 
11 
     | 
    
         
             
                from ormlambda.sql.types import TupleJoinType, ColumnType
         
     | 
| 
       13 
     | 
    
         
            -
                from ormlambda. 
     | 
| 
      
 12 
     | 
    
         
            +
                from ormlambda.components.join import JoinContext
         
     | 
| 
       14 
13 
     | 
    
         
             
                from ormlambda.common.enums import JoinType
         
     | 
| 
       15 
14 
     | 
    
         
             
                from ormlambda.sql.clause_info import ClauseInfo
         
     | 
| 
       16 
15 
     | 
    
         
             
                from ormlambda.sql.types import AliasType
         
     | 
| 
         @@ -249,33 +248,33 @@ class IStatements[T: Table](ABC): 
     | 
|
| 
       249 
248 
     | 
    
         
             
                # @overload
         
     | 
| 
       250 
249 
     | 
    
         
             
                # def select[TFlavour](self, selector: Optional[Callable[[T], tuple]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour], by: Optional[Enum] = ..., **kwargs) -> TFlavour: ...
         
     | 
| 
       251 
250 
     | 
    
         
             
                @overload
         
     | 
| 
       252 
     | 
    
         
            -
                def select[TRes](self, selector: SelectorFlavourType[T, TRes] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., **kwargs) -> tuple[TRes, ...]: ...
         
     | 
| 
      
 251 
     | 
    
         
            +
                def select[TRes](self, selector: SelectorFlavourType[T, TRes] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[TRes, ...]: ...
         
     | 
| 
       253 
252 
     | 
    
         
             
                @overload
         
     | 
| 
       254 
     | 
    
         
            -
                def select[*TRes](self, selector: SelectorFlavourType[T, tuple[*TRes]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., **kwargs) -> tuple[tuple[*TRes]]: ...
         
     | 
| 
      
 253 
     | 
    
         
            +
                def select[*TRes](self, selector: SelectorFlavourType[T, tuple[*TRes]] = ..., *, flavour: Type[tuple], by: Optional[Enum] = ..., alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[tuple[*TRes]]: ...
         
     | 
| 
       255 
254 
     | 
    
         
             
                @overload
         
     | 
| 
       256 
     | 
    
         
            -
                def select[TFlavour](self, selector: SelectorFlavourType[T, tuple] = ..., *, flavour: Type[TFlavour], by: Optional[Enum] = ..., **kwargs) -> tuple[TFlavour, ...]: ...
         
     | 
| 
      
 255 
     | 
    
         
            +
                def select[TFlavour](self, selector: SelectorFlavourType[T, tuple] = ..., *, flavour: Type[TFlavour], by: Optional[Enum] = ..., alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[TFlavour, ...]: ...
         
     | 
| 
       257 
256 
     | 
    
         | 
| 
       258 
257 
     | 
    
         
             
                @abstractmethod
         
     | 
| 
       259 
     | 
    
         
            -
                def select[TValue, TFlavour, P](self, selector: SelectorFlavourType[T, tuple[TValue, P]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour] = ..., by: JoinType = ..., **kwargs): ...
         
     | 
| 
      
 258 
     | 
    
         
            +
                def select[TValue, TFlavour, P](self, selector: SelectorFlavourType[T, tuple[TValue, P]] = ..., *, cast_to_tuple: bool = ..., flavour: Type[TFlavour] = ..., by: JoinType = ..., alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs): ...
         
     | 
| 
       260 
259 
     | 
    
         | 
| 
       261 
260 
     | 
    
         
             
                # endregion
         
     | 
| 
       262 
261 
     | 
    
         
             
                # region select_one
         
     | 
| 
       263 
262 
     | 
    
         
             
                @overload
         
     | 
| 
       264 
263 
     | 
    
         
             
                def select_one(self) -> T: ...
         
     | 
| 
       265 
264 
     | 
    
         
             
                @overload
         
     | 
| 
       266 
     | 
    
         
            -
                def select_one[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
         
     | 
| 
      
 265 
     | 
    
         
            +
                def select_one[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
         
     | 
| 
       267 
266 
     | 
    
         
             
                @overload
         
     | 
| 
       268 
267 
     | 
    
         
             
                def select_one[T1](self, selector: SelectorOneType[T, T1 | tuple[T1]], *, by: Optional[Enum] = ...) -> T1: ...
         
     | 
| 
       269 
268 
     | 
    
         
             
                @overload
         
     | 
| 
       270 
269 
     | 
    
         
             
                def select_one[*TRes](self, selector: SelectorOneType[T, tuple[*TRes]], *, by: Optional[Enum] = ...) -> tuple[*TRes]: ...
         
     | 
| 
       271 
270 
     | 
    
         
             
                @overload
         
     | 
| 
       272 
     | 
    
         
            -
                def select_one[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, **kwargs) -> T1: ...
         
     | 
| 
      
 271 
     | 
    
         
            +
                def select_one[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> T1: ...
         
     | 
| 
       273 
272 
     | 
    
         
             
                @overload
         
     | 
| 
       274 
     | 
    
         
            -
                def select_one[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
         
     | 
| 
      
 273 
     | 
    
         
            +
                def select_one[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
         
     | 
| 
       275 
274 
     | 
    
         
             
                @overload
         
     | 
| 
       276 
     | 
    
         
            -
                def select_one[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], **kwargs) -> tuple[*TRest]: ...
         
     | 
| 
      
 275 
     | 
    
         
            +
                def select_one[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[*TRest]: ...
         
     | 
| 
       277 
276 
     | 
    
         
             
                @overload
         
     | 
| 
       278 
     | 
    
         
            -
                def select_one[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
         
     | 
| 
      
 277 
     | 
    
         
            +
                def select_one[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
         
     | 
| 
       279 
278 
     | 
    
         
             
                @abstractmethod
         
     | 
| 
       280 
279 
     | 
    
         
             
                def select_one[TValue, TFlavour, *TRest](
         
     | 
| 
       281 
280 
     | 
    
         
             
                    self,
         
     | 
| 
         @@ -295,15 +294,15 @@ class IStatements[T: Table](ABC): 
     | 
|
| 
       295 
294 
     | 
    
         
             
                @overload
         
     | 
| 
       296 
295 
     | 
    
         
             
                def first[*TRes](self, selector: SelectorOneType[T, tuple[*TRes]], *, by: Optional[Enum] = ...) -> tuple[*TRes]: ...
         
     | 
| 
       297 
296 
     | 
    
         
             
                @overload
         
     | 
| 
       298 
     | 
    
         
            -
                def first[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
         
     | 
| 
      
 297 
     | 
    
         
            +
                def first[TFlavour](self, *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
         
     | 
| 
       299 
298 
     | 
    
         
             
                @overload
         
     | 
| 
       300 
     | 
    
         
            -
                def first[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, **kwargs) -> T1: ...
         
     | 
| 
      
 299 
     | 
    
         
            +
                def first[T1](self, selector: SelectorOneType[T, tuple[T1]], *, by: Optional[Enum] = ..., flavour: Type, alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> T1: ...
         
     | 
| 
       301 
300 
     | 
    
         
             
                @overload
         
     | 
| 
       302 
     | 
    
         
            -
                def first[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
         
     | 
| 
      
 301 
     | 
    
         
            +
                def first[T1, TFlavour](self, selector: SelectorOneType[T, T1], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
         
     | 
| 
       303 
302 
     | 
    
         
             
                @overload
         
     | 
| 
       304 
     | 
    
         
            -
                def first[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], **kwargs) -> tuple[*TRest]: ...
         
     | 
| 
      
 303 
     | 
    
         
            +
                def first[*TRest](self, selector: SelectorOneType[T, tuple[*TRest]], *, by: Optional[Enum] = ..., flavour: Type[tuple], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> tuple[*TRest]: ...
         
     | 
| 
       305 
304 
     | 
    
         
             
                @overload
         
     | 
| 
       306 
     | 
    
         
            -
                def first[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], **kwargs) -> TFlavour: ...
         
     | 
| 
      
 305 
     | 
    
         
            +
                def first[TFlavour](self, selector: SelectorOneType[T, tuple], *, by: Optional[Enum] = ..., flavour: Type[TFlavour], alias: Optional[AliasType[ClauseInfo[T]]] = ..., **kwargs) -> TFlavour: ...
         
     | 
| 
       307 
306 
     | 
    
         
             
                @abstractmethod
         
     | 
| 
       308 
307 
     | 
    
         
             
                def first[TValue, TFlavour, *TRest](
         
     | 
| 
       309 
308 
     | 
    
         
             
                    self,
         
     | 
| 
         @@ -316,13 +315,17 @@ class IStatements[T: Table](ABC): 
     | 
|
| 
       316 
315 
     | 
    
         
             
                # endregion
         
     | 
| 
       317 
316 
     | 
    
         | 
| 
       318 
317 
     | 
    
         
             
                # region groupby
         
     | 
| 
      
 318 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 319 
     | 
    
         
            +
                def groupby[TRepo](self, column: list[SelectCols[T, TRepo]]) -> IStatements[T]: ...
         
     | 
| 
      
 320 
     | 
    
         
            +
                @overload
         
     | 
| 
      
 321 
     | 
    
         
            +
                def groupby[TRepo](self, column: SelectCols[T, TRepo]) -> IStatements[T]: ...
         
     | 
| 
       319 
322 
     | 
    
         
             
                @abstractmethod
         
     | 
| 
       320 
     | 
    
         
            -
                def groupby[TRepo](self, column:  
     | 
| 
      
 323 
     | 
    
         
            +
                def groupby[TRepo](self, column: list[SelectCols[T, TRepo]] | SelectCols[T, TRepo]) -> IStatements[T]: ...
         
     | 
| 
       321 
324 
     | 
    
         | 
| 
       322 
325 
     | 
    
         
             
                # endregion
         
     | 
| 
       323 
326 
     | 
    
         | 
| 
       324 
327 
     | 
    
         
             
                @abstractmethod
         
     | 
| 
       325 
     | 
    
         
            -
                def alias[TProp](self, column:  
     | 
| 
      
 328 
     | 
    
         
            +
                def alias[TProp](self, column: SelectCols[T, TProp], alias: AliasType[ClauseInfo[T]]) -> ClauseInfo[T]: ...
         
     | 
| 
       326 
329 
     | 
    
         | 
| 
       327 
330 
     | 
    
         | 
| 
       328 
331 
     | 
    
         
             
            class IStatements_two_generic[T, TPool](IStatements[T]):
         
     | 
| 
         @@ -2,7 +2,8 @@ from __future__ import annotations 
     | 
|
| 
       2 
2 
     | 
    
         
             
            import sys
         
     | 
| 
       3 
3 
     | 
    
         
             
            from pathlib import Path
         
     | 
| 
       4 
4 
     | 
    
         
             
            from typing import Optional, Type, TYPE_CHECKING
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # from collections import defaultdict
         
     | 
| 
       6 
7 
     | 
    
         
             
            import importlib.util
         
     | 
| 
       7 
8 
     | 
    
         
             
            import inspect
         
     | 
| 
       8 
9 
     | 
    
         
             
            import re
         
     | 
| 
         @@ -12,7 +13,7 @@ if TYPE_CHECKING: 
     | 
|
| 
       12 
13 
     | 
    
         | 
| 
       13 
14 
     | 
    
         | 
| 
       14 
15 
     | 
    
         
             
            # from ormlambda import ForeignKey
         
     | 
| 
       15 
     | 
    
         
            -
            from .dfs_traversal import DFSTraversal
         
     | 
| 
      
 16 
     | 
    
         
            +
            # from .dfs_traversal import DFSTraversal
         
     | 
| 
       16 
17 
     | 
    
         | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
19 
     | 
    
         
             
            class Node:
         
     |