| 8 | ModelT = TypeVar('ModelT', bound=SQLModel) |
| 9 | |
| 10 | class Paginator: |
| 11 | def __init__(self, session: Session): |
| 12 | self.session = session |
| 13 | def _process_result_row(self, row: Row) -> Dict[str, Any]: |
| 14 | result_dict = {} |
| 15 | if isinstance(row, int): |
| 16 | return {'id': row} |
| 17 | if isinstance(row, SQLModel) and not hasattr(row, '_fields'): |
| 18 | return row.model_dump() |
| 19 | for item, key in zip(row, row._fields): |
| 20 | if isinstance(item, SQLModel): |
| 21 | result_dict.update(item.model_dump()) |
| 22 | else: |
| 23 | result_dict[key] = item |
| 24 | |
| 25 | return result_dict |
| 26 | async def paginate( |
| 27 | self, |
| 28 | stmt: Union[Select, SelectOfScalar, Type[ModelT]], |
| 29 | page: int = 1, |
| 30 | size: int = 20, |
| 31 | order_by: Optional[str] = None, |
| 32 | desc: bool = False, |
| 33 | **filters |
| 34 | ) -> tuple[Sequence[Any], int]: |
| 35 | offset = (page - 1) * size |
| 36 | single_model: bool = False |
| 37 | if isinstance(stmt, type) and issubclass(stmt, SQLModel): |
| 38 | stmt = select(stmt) |
| 39 | single_model = True |
| 40 | |
| 41 | # 应用过滤条件 |
| 42 | for field, value in filters.items(): |
| 43 | if value is not None: |
| 44 | # 处理关联模型的字段 (如 user.name) |
| 45 | if '.' in field: |
| 46 | related_model, related_field = field.split('.') |
| 47 | # 这里需要根据实际关联关系调整 |
| 48 | stmt = stmt.where(getattr(getattr(stmt.selected_columns, related_model), related_field) == value) |
| 49 | else: |
| 50 | stmt = stmt.where(getattr(stmt.selected_columns, field) == value) |
| 51 | |
| 52 | # 应用排序 |
| 53 | if order_by: |
| 54 | if '.' in order_by: |
| 55 | related_model, related_field = order_by.split('.') |
| 56 | column = getattr(getattr(stmt.selected_columns, related_model), related_field) |
| 57 | else: |
| 58 | column = getattr(stmt.selected_columns, order_by) |
| 59 | stmt = stmt.order_by(column.desc() if desc else column.asc()) |
| 60 | |
| 61 | # 计算总数 |
| 62 | """ count_stmt = stmt.with_only_columns(func.count(), maintain_column_froms=True) |
| 63 | result = self.session.exec(count_stmt) |
| 64 | total: int = result.first() """ |
| 65 | count_stmt = select(func.count()).select_from(stmt.subquery()) |
| 66 | total_result = self.session.exec(count_stmt) |
| 67 | total: int = total_result.first() |
no outgoing calls
no test coverage detected