72 lines
2.3 KiB
Python
72 lines
2.3 KiB
Python
"""fin_product 产品仓储:列表搜索(关键字/类型/风险/状态筛选 + 排序 + 分页)。"""
|
|||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from sqlalchemy import or_, select
|
||
|
|
|
||
|
|
from model.fin_product import FinProduct
|
||
|
|
from repositories.base import BaseRepository
|
||
|
|
from utils.exceptions import ParamError
|
||
|
|
|
||
|
|
# 排序字段白名单:防止 sort_by 注入,字符串映射到 ORM 列(不拼 SQL)
|
||
|
|
SORTABLE_FIELDS = {
|
||
|
|
"expected_return": FinProduct.expected_return,
|
||
|
|
"nav": FinProduct.nav,
|
||
|
|
"fee_rate": FinProduct.fee_rate,
|
||
|
|
"risk_level": FinProduct.risk_level,
|
||
|
|
"create_time": FinProduct.create_time,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
class ProductRepo(BaseRepository):
|
||
|
|
model = FinProduct
|
||
|
|
|
||
|
|
async def get_by_code(self, product_code: str) -> FinProduct | None:
|
||
|
|
return await self.db.scalar(
|
||
|
|
select(FinProduct).where(FinProduct.product_code == product_code)
|
||
|
|
)
|
||
|
|
|
||
|
|
async def search(
|
||
|
|
self,
|
||
|
|
*,
|
||
|
|
keyword: str | None = None,
|
||
|
|
product_type: str | None = None,
|
||
|
|
risk_level: str | None = None,
|
||
|
|
status: str | None = "在售",
|
||
|
|
sort_by: str = "create_time",
|
||
|
|
sort_order: str = "desc",
|
||
|
|
limit: int = 10,
|
||
|
|
offset: int = 0,
|
||
|
|
) -> tuple[list[FinProduct], int]:
|
||
|
|
conds = []
|
||
|
|
if status and status != "全部":
|
||
|
|
conds.append(FinProduct.status == status)
|
||
|
|
if product_type:
|
||
|
|
conds.append(FinProduct.product_type == product_type)
|
||
|
|
if risk_level:
|
||
|
|
conds.append(FinProduct.risk_level == risk_level)
|
||
|
|
if keyword:
|
||
|
|
like = f"%{keyword}%"
|
||
|
|
conds.append(
|
||
|
|
or_(
|
||
|
|
FinProduct.product_code.like(like),
|
||
|
|
FinProduct.product_name.like(like),
|
||
|
|
FinProduct.fund_manager.like(like),
|
||
|
|
)
|
||
|
|
)
|
||
|
|
|
||
|
|
col = SORTABLE_FIELDS.get(sort_by)
|
||
|
|
if col is None:
|
||
|
|
raise ParamError(f"不支持的排序字段: {sort_by}")
|
||
|
|
order_col = col.desc() if sort_order == "desc" else col.asc()
|
||
|
|
|
||
|
|
stmt = (
|
||
|
|
select(FinProduct)
|
||
|
|
.where(*conds)
|
||
|
|
.order_by(order_col)
|
||
|
|
.limit(limit)
|
||
|
|
.offset(offset)
|
||
|
|
)
|
||
|
|
items = list((await self.db.scalars(stmt)).all())
|
||
|
|
total = await self.count(where=conds)
|
||
|
|
return items, total
|