from typing import Optional, Tuple from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import aliased from app.models.generated_resource import GeneratedResource from app.models.resources_material import ResourcesMaterial from app.schemas.resources_material import GeneratedResourceOut, ResourcesMaterialOut from app.services.resource_signed_url_service import build_resource_signed_url async def get_resources_material_list( db: AsyncSession, advertiser_id: Optional[str] = None, material_id: Optional[str] = None, upload_id: Optional[str] = None, file_name: Optional[str] = None, resource_type: Optional[str] = None, page: int = 1, page_size: int = 20, user_id: Optional[str] = None, ) -> Tuple[list[ResourcesMaterialOut], int]: resource_alias = aliased(GeneratedResource) query = select(ResourcesMaterial).where(ResourcesMaterial.deleted_at.is_(None)) if user_id: query = query.where(ResourcesMaterial.user_id == user_id) if advertiser_id: query = query.where(ResourcesMaterial.advertiser_id == advertiser_id) if material_id: query = query.where(ResourcesMaterial.material_id == material_id) if upload_id: query = query.where(ResourcesMaterial.upload_id == upload_id) if resource_type: query = query.where(ResourcesMaterial.resource_type == resource_type) if file_name: query = query.join( resource_alias, (ResourcesMaterial.target_id == resource_alias.id) & (ResourcesMaterial.target_table == "generated_resources") & (resource_alias.deleted_at.is_(None)), isouter=True ).where(resource_alias.file_name.like(f"%{file_name}%")) total = (await db.execute(select(func.count()).select_from(query.subquery()))).scalar_one() query = query.order_by(ResourcesMaterial.created_at.desc()) query = query.offset((page - 1) * page_size).limit(page_size) result = await db.execute(query) materials = result.scalars().all() target_ids = [material.target_id for material in materials if material.target_id and material.target_table == "generated_resources"] resource_map = {} if target_ids: resource_query = select(GeneratedResource).where( GeneratedResource.id.in_(target_ids), GeneratedResource.deleted_at.is_(None) ) resource_result = await db.execute(resource_query) resources = resource_result.scalars().all() resource_map = {resource.id: resource for resource in resources} items = [] for material in materials: resource = None if material.target_id and material.target_table == "generated_resources": generated_resource = resource_map.get(material.target_id) if generated_resource: resource = GeneratedResourceOut( file_name=generated_resource.file_name, resource_url = build_resource_signed_url(generated_resource.resource_url) if generated_resource.resource_url else "", storage_type=generated_resource.storage_type, file_size_bytes=generated_resource.file_size_bytes, source_model=generated_resource.source_model, source_model_module=generated_resource.source_model_module, source_id=generated_resource.source_id, engine_id=generated_resource.engine_id, engine_type=generated_resource.engine_type, provider=generated_resource.provider, model_name=generated_resource.model_name, generated_at=generated_resource.generated_at, resource_month=generated_resource.resource_month, created_at=generated_resource.created_at, ) items.append(ResourcesMaterialOut( id=material.id, oauth_id=material.oauth_id, advertiser_id=material.advertiser_id, target_table=material.target_table, target_id=material.target_id, material_id=material.material_id, upload_id=material.upload_id, resource_type=material.resource_type, user_id=material.user_id, task_id=material.task_id, note=material.note, status=material.status, pre_result=material.pre_result, pre_test_template_id=material.pre_test_template_id, created_at=material.created_at, updated_at=material.updated_at, resource=resource, )) return items, total