1
1
#!/usr/bin/env python3
2
2
# -*- coding: utf-8 -*-
3
- from typing import Any , Generic , Sequence , Type , TypeVar
3
+ from typing import Any , Generic , Literal , Sequence , Type , TypeVar
4
4
5
5
from pydantic import BaseModel
6
- from sqlalchemy import Row , RowMapping , select
6
+ from sqlalchemy import Row , RowMapping , and_ , asc , desc , or_ , select
7
7
from sqlalchemy import delete as sa_delete
8
8
from sqlalchemy import update as sa_update
9
9
from sqlalchemy .ext .asyncio import AsyncSession
10
10
11
- from sqlalchemy_crud_plus .errors import ModelColumnError
11
+ from sqlalchemy_crud_plus .errors import ModelColumnError , SelectExpressionError
12
12
13
13
_Model = TypeVar ('_Model' )
14
14
_CreateSchema = TypeVar ('_CreateSchema' , bound = BaseModel )
@@ -59,7 +59,34 @@ async def select_model_by_column(self, session: AsyncSession, column: str, colum
59
59
query = await session .execute (select (self .model ).where (model_column == column_value )) # type: ignore
60
60
return query .scalars ().first ()
61
61
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 ()
63
90
64
91
async def select_models (self , session : AsyncSession ) -> Sequence [Row | RowMapping | Any ] | None :
65
92
"""
@@ -71,6 +98,41 @@ async def select_models(self, session: AsyncSession) -> Sequence[Row | RowMappin
71
98
query = await session .execute (select (self .model ))
72
99
return query .scalars ().all ()
73
100
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
+
74
136
async def update_model (self , session : AsyncSession , pk : int , obj : _UpdateSchema | dict [str , Any ], ** kwargs ) -> int :
75
137
"""
76
138
Update an instance of a model
0 commit comments