44
55import sqlalchemy as sa
66from aiohttp import web
7- from common_library .exclude import UnSet , as_dict_exclude_unset
7+ from common_library .exclude import UnSet , as_dict_exclude_unset , is_set
88from models_library .folders import (
99 FolderDB ,
1010 FolderID ,
3535from sqlalchemy .ext .asyncio import AsyncConnection
3636from sqlalchemy .orm import aliased
3737from sqlalchemy .sql import ColumnElement , CompoundSelect , Select , asc , desc , select
38+ from sqlalchemy .sql .selectable import GenerativeSelect
3839
3940from ..db .plugin import get_asyncpg_engine
4041from .errors import FolderAccessForbiddenError , FolderNotFoundError
@@ -155,6 +156,17 @@ def _create_shared_workspace_query(
155156 return shared_workspace_query
156157
157158
159+ def _set_ordering (
160+ base_query : GenerativeSelect ,
161+ order_by : OrderBy ,
162+ ) -> GenerativeSelect :
163+ if order_by .direction == OrderDirection .ASC :
164+ list_query = base_query .order_by (asc (getattr (folders_v2 .c , order_by .field )))
165+ else :
166+ list_query = base_query .order_by (desc (getattr (folders_v2 .c , order_by .field )))
167+ return list_query
168+
169+
158170async def list_ ( # pylint: disable=too-many-arguments,too-many-branches
159171 app : web .Application ,
160172 connection : AsyncConnection | None = None ,
@@ -235,12 +247,7 @@ async def list_( # pylint: disable=too-many-arguments,too-many-branches
235247 count_query = select (func .count ()).select_from (combined_query .subquery ())
236248
237249 # Ordering and pagination
238- if order_by .direction == OrderDirection .ASC :
239- list_query = combined_query .order_by (asc (getattr (folders_v2 .c , order_by .field )))
240- else :
241- list_query = combined_query .order_by (
242- desc (getattr (folders_v2 .c , order_by .field ))
243- )
250+ list_query = _set_ordering (combined_query , order_by = order_by )
244251 list_query = list_query .offset (offset ).limit (limit )
245252
246253 async with pass_or_acquire_connection (get_asyncpg_engine (app ), connection ) as conn :
@@ -253,6 +260,50 @@ async def list_( # pylint: disable=too-many-arguments,too-many-branches
253260 return cast (int , total_count ), folders
254261
255262
263+ async def list_trashed_folders (
264+ app : web .Application ,
265+ connection : AsyncConnection | None = None ,
266+ * ,
267+ # filter
268+ trashed_explicitly : bool | UnSet = UnSet .VALUE ,
269+ trashed_until : datetime | UnSet = UnSet .VALUE ,
270+ # pagination
271+ offset : NonNegativeInt ,
272+ limit : int ,
273+ # order
274+ order_by : OrderBy ,
275+ ) -> tuple [int , list [FolderDB ]]:
276+ """
277+ NOTE: this is app-wide i.e. no product, user or workspace filtered
278+ TODO: check with MD about workspaces
279+ """
280+ base_query = select (_FOLDER_DB_MODEL_COLS ).where (folders_v2 .c .trashed .is_not (None ))
281+
282+ if is_set (trashed_explicitly ):
283+ assert isinstance (trashed_explicitly , bool ) # nosec
284+ base_query = base_query .where (
285+ folders_v2 .c .trashed_explicitly .is_ (trashed_explicitly )
286+ )
287+
288+ if is_set (trashed_until ):
289+ assert isinstance (trashed_until , datetime ) # nosec
290+ base_query = base_query .where (folders_v2 .c .trashed < trashed_until )
291+
292+ # Select total count from base_query
293+ count_query = select (func .count ()).select_from (base_query .subquery ())
294+
295+ # Ordering and pagination
296+ list_query = _set_ordering (base_query , order_by )
297+ list_query = list_query .offset (offset ).limit (limit )
298+
299+ async with pass_or_acquire_connection (get_asyncpg_engine (app ), connection ) as conn :
300+ total_count = await conn .scalar (count_query )
301+
302+ result = await conn .stream (list_query )
303+ folders : list [FolderDB ] = [FolderDB .model_validate (row ) async for row in result ]
304+ return cast (int , total_count ), folders
305+
306+
256307def _create_base_select_query (folder_id : FolderID , product_name : ProductName ) -> Select :
257308 return select (* _FOLDER_DB_MODEL_COLS ,).where (
258309 (folders_v2 .c .product_name == product_name )
0 commit comments