11#!/usr/bin/env python3
22# -*- coding: utf-8 -*-
3- from typing import Any , Generic , Sequence , Type , TypeVar
3+ from typing import Any , Generic , Literal , Sequence , Type , TypeVar
44
55from pydantic import BaseModel
6- from sqlalchemy import Row , RowMapping , select
6+ from sqlalchemy import Row , RowMapping , and_ , asc , desc , or_ , select
77from sqlalchemy import delete as sa_delete
88from sqlalchemy import update as sa_update
99from sqlalchemy .ext .asyncio import AsyncSession
1010
11- from sqlalchemy_crud_plus .errors import ModelColumnError
11+ from sqlalchemy_crud_plus .errors import ModelColumnError , SelectExpressionError
1212
1313_Model = TypeVar ('_Model' )
1414_CreateSchema = TypeVar ('_CreateSchema' , bound = BaseModel )
@@ -59,7 +59,34 @@ async def select_model_by_column(self, session: AsyncSession, column: str, colum
5959 query = await session .execute (select (self .model ).where (model_column == column_value )) # type: ignore
6060 return query .scalars ().first ()
6161 else :
62- raise ModelColumnError ('Model column not found' )
62+ raise ModelColumnError (f'Model column { column } is not found' )
63+
64+ async def select_model_by_columns (
65+ self , session : AsyncSession , expression : Literal ['and' , 'or' ] = 'and' , ** conditions
66+ ) -> _Model | None :
67+ """
68+ Query by columns
69+
70+ :param session:
71+ :param expression:
72+ :param conditions: Query conditions, format:column1=value1, column2=value2
73+ :return:
74+ """
75+ where_list = []
76+ for column , value in conditions .items ():
77+ if hasattr (self .model , column ):
78+ model_column = getattr (self .model , column )
79+ where_list .append (model_column == value )
80+ else :
81+ raise ModelColumnError (f'Model column { column } is not found' )
82+ match expression :
83+ case 'and' :
84+ query = await session .execute (select (self .model ).where (and_ (* where_list )))
85+ case 'or' :
86+ query = await session .execute (select (self .model ).where (or_ (* where_list )))
87+ case _:
88+ raise SelectExpressionError (f'select expression { expression } is not supported' )
89+ return query .scalars ().first ()
6390
6491 async def select_models (self , session : AsyncSession ) -> Sequence [Row | RowMapping | Any ] | None :
6592 """
@@ -71,6 +98,41 @@ async def select_models(self, session: AsyncSession) -> Sequence[Row | RowMappin
7198 query = await session .execute (select (self .model ))
7299 return query .scalars ().all ()
73100
101+ async def select_models_order (
102+ self ,
103+ session : AsyncSession ,
104+ * columns ,
105+ model_sort : Literal ['skip' , 'asc' , 'desc' ] = 'skip' ,
106+ ) -> Sequence [Row | RowMapping | Any ] | None :
107+ """
108+ Query all rows asc or desc
109+
110+ :param session:
111+ :param columns:
112+ :param model_sort:
113+ :return:
114+ """
115+ if model_sort != 'skip' :
116+ if len (columns ) != 1 :
117+ raise SelectExpressionError ('ACS and DESC only allow you to specify one column for sorting' )
118+ sort_list = []
119+ for column in columns :
120+ if hasattr (self .model , column ):
121+ model_column = getattr (self .model , column )
122+ sort_list .append (model_column )
123+ else :
124+ raise ModelColumnError (f'Model column { column } is not found' )
125+ match model_sort :
126+ case 'skip' :
127+ query = await session .execute (select (self .model ).order_by (* sort_list ))
128+ case 'asc' :
129+ query = await session .execute (select (self .model ).order_by (asc (* sort_list )))
130+ case 'desc' :
131+ query = await session .execute (select (self .model ).order_by (desc (* sort_list )))
132+ case _:
133+ raise SelectExpressionError (f'select sort expression { model_sort } is not supported' )
134+ return query .scalars ().all ()
135+
74136 async def update_model (self , session : AsyncSession , pk : int , obj : _UpdateSchema | dict [str , Any ], ** kwargs ) -> int :
75137 """
76138 Update an instance of a model
0 commit comments