paginate-fastapi 0.1.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- paginate_fastapi-0.1.0.dist-info/LICENSE +21 -0
- paginate_fastapi-0.1.0.dist-info/METADATA +212 -0
- paginate_fastapi-0.1.0.dist-info/RECORD +7 -0
- paginate_fastapi-0.1.0.dist-info/WHEEL +4 -0
- pagination/__init__.py +31 -0
- pagination/middleware.py +182 -0
- pagination/models.py +122 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Ritvik Dayal
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
@@ -0,0 +1,212 @@
|
|
1
|
+
Metadata-Version: 2.3
|
2
|
+
Name: paginate-fastapi
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A simple and efficient pagination library for FastAPI applications
|
5
|
+
License: MIT
|
6
|
+
Keywords: fastapi,sqlmodel,pagination,async,filtering,sorting
|
7
|
+
Author: Ritvik Dayal
|
8
|
+
Author-email: ritvikr1605@gmail.com
|
9
|
+
Requires-Python: >=3.11
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
11
|
+
Classifier: Framework :: FastAPI
|
12
|
+
Classifier: Intended Audience :: Developers
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
14
|
+
Classifier: Operating System :: OS Independent
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
18
|
+
Classifier: Typing :: Typed
|
19
|
+
Provides-Extra: dev
|
20
|
+
Requires-Dist: aiosqlite (>=0.20.0) ; extra == "dev"
|
21
|
+
Requires-Dist: black (>=24.1.0) ; extra == "dev"
|
22
|
+
Requires-Dist: fastapi (>=0.100.0)
|
23
|
+
Requires-Dist: fastapi[all] (>=0.100.0) ; extra == "dev"
|
24
|
+
Requires-Dist: httpx (>=0.27.0) ; extra == "dev"
|
25
|
+
Requires-Dist: mypy (>=1.8.0) ; extra == "dev"
|
26
|
+
Requires-Dist: pre-commit (>=4.1.0,<5.0.0)
|
27
|
+
Requires-Dist: pydantic (>=2.0.0)
|
28
|
+
Requires-Dist: pytest (>=8.0.0) ; extra == "dev"
|
29
|
+
Requires-Dist: pytest-asyncio (>=0.23.0) ; extra == "dev"
|
30
|
+
Requires-Dist: pytest-cov (>=4.1.0) ; extra == "dev"
|
31
|
+
Requires-Dist: ruff (>=0.9.7,<0.10.0) ; extra == "dev"
|
32
|
+
Requires-Dist: sqlmodel (>=0.0.8)
|
33
|
+
Project-URL: Documentation, https://github.com/ritvikdayal/paginate-fastapi#readme
|
34
|
+
Project-URL: Homepage, https://github.com/ritvikdayal/paginate-fastapi
|
35
|
+
Project-URL: Issues, https://github.com/ritvikdayal/paginate-fastapi/issues
|
36
|
+
Project-URL: Repository, https://github.com/ritvikdayal/paginate-fastapi.git
|
37
|
+
Description-Content-Type: text/markdown
|
38
|
+
|
39
|
+
# Paginate FastAPI
|
40
|
+
|
41
|
+
[](https://badge.fury.io/py/paginate-fastapi)
|
42
|
+
[](https://opensource.org/licenses/MIT)
|
43
|
+
[](https://www.python.org/downloads/)
|
44
|
+
|
45
|
+
A simple and efficient pagination library for FastAPI applications.
|
46
|
+
|
47
|
+
## Features
|
48
|
+
|
49
|
+
- Easy-to-use pagination with FastAPI
|
50
|
+
- Async support out of the box
|
51
|
+
- Flexible filtering options
|
52
|
+
- Customizable sorting
|
53
|
+
- Type-safe with full type hints
|
54
|
+
- Compatible with FastAPI
|
55
|
+
|
56
|
+
## Installation
|
57
|
+
|
58
|
+
### Using Poetry
|
59
|
+
```bash
|
60
|
+
poetry add paginate-fastapi
|
61
|
+
```
|
62
|
+
|
63
|
+
### Using Pip
|
64
|
+
```bash
|
65
|
+
pip install paginate-fastapi
|
66
|
+
```
|
67
|
+
|
68
|
+
## Quick Start
|
69
|
+
|
70
|
+
```python
|
71
|
+
from fastapi import FastAPI, Depends
|
72
|
+
from sqlmodel import SQLModel, Field
|
73
|
+
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
|
74
|
+
from pagination import PaginationMiddleware, PaginationParams
|
75
|
+
|
76
|
+
app = FastAPI()
|
77
|
+
|
78
|
+
# Initialize your database
|
79
|
+
engine = create_async_engine("sqlite+aiosqlite:///database.db")
|
80
|
+
|
81
|
+
async def get_session() -> AsyncSession:
|
82
|
+
async with AsyncSession(engine) as session:
|
83
|
+
yield session
|
84
|
+
|
85
|
+
paginator = PaginationMiddleware(get_session)
|
86
|
+
|
87
|
+
# Define your model
|
88
|
+
class User(SQLModel, table=True):
|
89
|
+
id: int = Field(primary_key=True)
|
90
|
+
name: str
|
91
|
+
email: str
|
92
|
+
age: int
|
93
|
+
|
94
|
+
# Add pagination to your endpoint
|
95
|
+
@app.get("/users/")
|
96
|
+
async def get_users(
|
97
|
+
pagination: PaginationParams = Depends(),
|
98
|
+
paginator: PaginationMiddleware = Depends(lambda: paginator),
|
99
|
+
):
|
100
|
+
return await paginator.paginate(User, pagination)
|
101
|
+
```
|
102
|
+
|
103
|
+
### Sample Request and Response
|
104
|
+
|
105
|
+
```bash
|
106
|
+
curl -X GET "http://localhost:8000/users/?page=1&page_size=10"
|
107
|
+
```
|
108
|
+
|
109
|
+
```json
|
110
|
+
{
|
111
|
+
"items": [
|
112
|
+
{
|
113
|
+
"id": 1,
|
114
|
+
"name": "John Doe",
|
115
|
+
"email": "john.doe@example.com",
|
116
|
+
"age": 30
|
117
|
+
}
|
118
|
+
],
|
119
|
+
"total": 100,
|
120
|
+
"page": 1,
|
121
|
+
"page_size": 10,
|
122
|
+
"pages": 10,
|
123
|
+
"has_next": true,
|
124
|
+
"has_previous": false
|
125
|
+
}
|
126
|
+
```
|
127
|
+
|
128
|
+
### Sorting
|
129
|
+
|
130
|
+
```bash
|
131
|
+
# Sort by name ascending
|
132
|
+
users/?sort_by=name&sort_order=asc
|
133
|
+
|
134
|
+
# Sort by age descending
|
135
|
+
users/?sort_by=age&sort_order=desc
|
136
|
+
```
|
137
|
+
|
138
|
+
### Filtering
|
139
|
+
|
140
|
+
```bash
|
141
|
+
# Filter users by age greater than 30
|
142
|
+
users/?filter_field=age&filter_operator=gt&filter_value=30
|
143
|
+
|
144
|
+
# Filter users by name containing "John"
|
145
|
+
users/?filter_field=name&filter_operator=like&filter_value=John
|
146
|
+
|
147
|
+
# Filter users by age in a list
|
148
|
+
users/?filter_field=age&filter_operator=in&filter_value=[25,30,35]
|
149
|
+
```
|
150
|
+
|
151
|
+
### Available Filter Operators
|
152
|
+
|
153
|
+
- `eq`: Equal to
|
154
|
+
- `ne`: Not equal to
|
155
|
+
- `gt`: Greater than
|
156
|
+
- `lt`: Less than
|
157
|
+
- `ge`: Greater than or equal to
|
158
|
+
- `le`: Less than or equal to
|
159
|
+
- `like`: Contains (case-sensitive)
|
160
|
+
- `ilike`: Contains (case-insensitive)
|
161
|
+
- `in`: In list of values
|
162
|
+
- `not_in`: Not in list of values
|
163
|
+
|
164
|
+
## Development
|
165
|
+
|
166
|
+
### Setup
|
167
|
+
|
168
|
+
```bash
|
169
|
+
# Clone the repository
|
170
|
+
git clone https://github.com/ritvikdayal/paginate-fastapi.git
|
171
|
+
cd paginate-fastapi
|
172
|
+
|
173
|
+
# Install dependencies
|
174
|
+
poetry install --with dev
|
175
|
+
|
176
|
+
# Setup pre-commit hooks (optional)
|
177
|
+
make setup-hooks
|
178
|
+
```
|
179
|
+
|
180
|
+
### Running Tests
|
181
|
+
|
182
|
+
```bash
|
183
|
+
make test
|
184
|
+
```
|
185
|
+
|
186
|
+
### Code Quality
|
187
|
+
|
188
|
+
```bash
|
189
|
+
# Run all code quality checks
|
190
|
+
make pre-commit
|
191
|
+
|
192
|
+
# Format code only
|
193
|
+
make format
|
194
|
+
|
195
|
+
# Run linters only
|
196
|
+
make lint
|
197
|
+
```
|
198
|
+
|
199
|
+
## Contributing
|
200
|
+
|
201
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
202
|
+
|
203
|
+
1. Fork the repository
|
204
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
205
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
206
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
207
|
+
5. Open a Pull Request
|
208
|
+
|
209
|
+
## License
|
210
|
+
|
211
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
212
|
+
|
@@ -0,0 +1,7 @@
|
|
1
|
+
pagination/__init__.py,sha256=Lr6iRikRx03cnFaV6n5e9s1yDAEOracpxbx6ImOA-v4,827
|
2
|
+
pagination/middleware.py,sha256=7PAzExzv55gBrZQORuJJORd1VTas8b-Oed-jm3eLquA,6261
|
3
|
+
pagination/models.py,sha256=nSASwuG-rlrti2RWI4Oj6epDiYGV0qCQmcijqGfMRbU,3248
|
4
|
+
paginate_fastapi-0.1.0.dist-info/LICENSE,sha256=04BsGfNMsEqA705-GhDsFirDIQyWUiCWJFx0h2ss6yE,1079
|
5
|
+
paginate_fastapi-0.1.0.dist-info/METADATA,sha256=TMdNZICsznUU2JXVHSeOeYNg_KTLAqP0TFXnVRR3QeU,5387
|
6
|
+
paginate_fastapi-0.1.0.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
7
|
+
paginate_fastapi-0.1.0.dist-info/RECORD,,
|
pagination/__init__.py
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
"""
|
2
|
+
FastAPI SQLModel Pagination Library
|
3
|
+
|
4
|
+
A library for adding pagination, filtering, and sorting capabilities
|
5
|
+
to FastAPI applications using SQLModel.
|
6
|
+
|
7
|
+
Example:
|
8
|
+
from fastapi import FastAPI, Depends
|
9
|
+
from pagination import PaginationMiddleware, PaginationParams
|
10
|
+
|
11
|
+
app = FastAPI()
|
12
|
+
paginator = PaginationMiddleware(get_session)
|
13
|
+
|
14
|
+
@app.get("/items/")
|
15
|
+
async def get_items(
|
16
|
+
pagination: PaginationParams = Depends(),
|
17
|
+
paginator: PaginationMiddleware = Depends(lambda: paginator),
|
18
|
+
):
|
19
|
+
return await paginator.paginate(Item, pagination)
|
20
|
+
"""
|
21
|
+
|
22
|
+
from .middleware import PaginationMiddleware
|
23
|
+
from .models import FilterOperator, PageResponse, PaginationParams, SortOrder
|
24
|
+
|
25
|
+
__all__ = [
|
26
|
+
"FilterOperator",
|
27
|
+
"PageResponse",
|
28
|
+
"PaginationMiddleware",
|
29
|
+
"PaginationParams",
|
30
|
+
"SortOrder",
|
31
|
+
]
|
pagination/middleware.py
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
"""
|
2
|
+
Pagination middleware for FastAPI applications.
|
3
|
+
|
4
|
+
This module provides the core pagination functionality, including:
|
5
|
+
- Async session handling
|
6
|
+
- Query building with filters
|
7
|
+
- Sorting implementation
|
8
|
+
- Pagination calculation
|
9
|
+
|
10
|
+
The middleware can be used with any SQLModel-based FastAPI application
|
11
|
+
to add pagination, filtering, and sorting capabilities.
|
12
|
+
"""
|
13
|
+
|
14
|
+
from collections.abc import AsyncGenerator, Callable
|
15
|
+
from contextlib import asynccontextmanager
|
16
|
+
|
17
|
+
from sqlalchemy import asc, desc
|
18
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
19
|
+
from sqlalchemy.sql import Select
|
20
|
+
from sqlmodel import SQLModel, func, select
|
21
|
+
|
22
|
+
from .models import FilterOperator, PageResponse, PaginationParams, SortOrder
|
23
|
+
|
24
|
+
|
25
|
+
class PaginationMiddleware:
|
26
|
+
"""
|
27
|
+
Middleware for handling pagination in FastAPI applications.
|
28
|
+
|
29
|
+
This class provides methods to paginate SQLModel queries with
|
30
|
+
support for filtering and sorting. It handles both async context
|
31
|
+
managers and async generators for database sessions.
|
32
|
+
|
33
|
+
Attributes:
|
34
|
+
session_maker: Callable that provides database sessions
|
35
|
+
default_page_size: Default number of items per page
|
36
|
+
"""
|
37
|
+
|
38
|
+
def __init__(
|
39
|
+
self,
|
40
|
+
session_maker: Callable[[], AsyncSession | AsyncGenerator[AsyncSession, None]],
|
41
|
+
default_page_size: int = 10,
|
42
|
+
):
|
43
|
+
"""
|
44
|
+
Initialize the pagination middleware.
|
45
|
+
|
46
|
+
Args:
|
47
|
+
session_maker: Function that returns a database session
|
48
|
+
default_page_size: Default number of items per page
|
49
|
+
"""
|
50
|
+
self.session_maker = session_maker
|
51
|
+
self.default_page_size = default_page_size
|
52
|
+
|
53
|
+
@asynccontextmanager
|
54
|
+
async def get_session(self) -> AsyncGenerator[AsyncSession, None]:
|
55
|
+
"""
|
56
|
+
Get a database session using the session maker.
|
57
|
+
|
58
|
+
This method handles both async context managers and async generators,
|
59
|
+
making it compatible with FastAPI dependency injection.
|
60
|
+
|
61
|
+
Yields:
|
62
|
+
AsyncSession: Database session
|
63
|
+
"""
|
64
|
+
session_factory = self.session_maker()
|
65
|
+
if hasattr(session_factory, "__aenter__"):
|
66
|
+
async with session_factory as session:
|
67
|
+
yield session
|
68
|
+
else:
|
69
|
+
try:
|
70
|
+
session = await anext(session_factory)
|
71
|
+
yield session
|
72
|
+
finally:
|
73
|
+
try:
|
74
|
+
await session_factory.aclose()
|
75
|
+
except RuntimeError as ex:
|
76
|
+
if "already closed" not in str(ex):
|
77
|
+
raise ex
|
78
|
+
|
79
|
+
def _apply_filter(
|
80
|
+
self, query: Select, model: type[SQLModel], params: PaginationParams
|
81
|
+
) -> Select:
|
82
|
+
"""
|
83
|
+
Apply filter conditions to the query.
|
84
|
+
|
85
|
+
Args:
|
86
|
+
query: Base SQLAlchemy select query
|
87
|
+
model: SQLModel class to query
|
88
|
+
params: Pagination parameters containing filter settings
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
Select: Query with filters applied
|
92
|
+
"""
|
93
|
+
if not all([params.filter_field, params.filter_operator, params.filter_value is not None]):
|
94
|
+
return query
|
95
|
+
|
96
|
+
field = getattr(model, params.filter_field)
|
97
|
+
|
98
|
+
filter_map = {
|
99
|
+
FilterOperator.EQ: lambda f, v: f == v,
|
100
|
+
FilterOperator.NEQ: lambda f, v: f != v,
|
101
|
+
FilterOperator.GT: lambda f, v: f > v,
|
102
|
+
FilterOperator.LT: lambda f, v: f < v,
|
103
|
+
FilterOperator.GTE: lambda f, v: f >= v,
|
104
|
+
FilterOperator.LTE: lambda f, v: f <= v,
|
105
|
+
FilterOperator.LIKE: lambda f, v: f.like(f"%{v}%"),
|
106
|
+
FilterOperator.ILIKE: lambda f, v: f.ilike(f"%{v}%"),
|
107
|
+
FilterOperator.IN: lambda f, v: f.in_(v),
|
108
|
+
FilterOperator.NOT_IN: lambda f, v: ~f.in_(v),
|
109
|
+
}
|
110
|
+
|
111
|
+
filter_func = filter_map[params.filter_operator]
|
112
|
+
return query.where(filter_func(field, params.filter_value))
|
113
|
+
|
114
|
+
def _apply_sort(self, query: Select, model: type[SQLModel], params: PaginationParams) -> Select:
|
115
|
+
"""
|
116
|
+
Apply sorting to the query.
|
117
|
+
|
118
|
+
Args:
|
119
|
+
query: Base SQLAlchemy select query
|
120
|
+
model: SQLModel class to query
|
121
|
+
params: Pagination parameters containing sort settings
|
122
|
+
|
123
|
+
Returns:
|
124
|
+
Select: Query with sorting applied
|
125
|
+
"""
|
126
|
+
if not params.sort_by:
|
127
|
+
return query
|
128
|
+
|
129
|
+
field = getattr(model, params.sort_by)
|
130
|
+
return query.order_by(desc(field) if params.sort_order == SortOrder.DESC else asc(field))
|
131
|
+
|
132
|
+
async def paginate(
|
133
|
+
self, model: type[SQLModel], params: PaginationParams | None = None
|
134
|
+
) -> PageResponse:
|
135
|
+
"""
|
136
|
+
Paginate a SQLModel query with optional filtering and sorting.
|
137
|
+
|
138
|
+
This method handles the complete pagination process:
|
139
|
+
1. Builds the base query
|
140
|
+
2. Applies any filters
|
141
|
+
3. Applies sorting
|
142
|
+
4. Calculates total count
|
143
|
+
5. Applies pagination
|
144
|
+
6. Returns formatted response
|
145
|
+
|
146
|
+
Args:
|
147
|
+
model: SQLModel class to paginate
|
148
|
+
params: Pagination, filtering, and sorting parameters
|
149
|
+
|
150
|
+
Returns:
|
151
|
+
PageResponse: Paginated results with metadata
|
152
|
+
"""
|
153
|
+
if params is None:
|
154
|
+
params = PaginationParams(page_size=self.default_page_size)
|
155
|
+
|
156
|
+
async with self.get_session() as session:
|
157
|
+
# Build query
|
158
|
+
query = select(model)
|
159
|
+
query = self._apply_filter(query, model, params)
|
160
|
+
query = self._apply_sort(query, model, params)
|
161
|
+
|
162
|
+
# Get total count
|
163
|
+
count_query = select(func.count()).select_from(query.subquery())
|
164
|
+
total = (await session.execute(count_query)).scalar() or 0
|
165
|
+
|
166
|
+
# Apply pagination
|
167
|
+
query = query.offset(params.offset).limit(params.page_size)
|
168
|
+
result = await session.execute(query)
|
169
|
+
items = result.scalars().all()
|
170
|
+
|
171
|
+
# Calculate pagination metadata
|
172
|
+
pages = (total + params.page_size - 1) // params.page_size if total > 0 else 0
|
173
|
+
|
174
|
+
return PageResponse(
|
175
|
+
items=items,
|
176
|
+
total=total,
|
177
|
+
page=params.page,
|
178
|
+
page_size=params.page_size,
|
179
|
+
pages=pages,
|
180
|
+
has_next=params.page < pages,
|
181
|
+
has_previous=params.page > 1,
|
182
|
+
)
|
pagination/models.py
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
"""
|
2
|
+
Models for the pagination library.
|
3
|
+
|
4
|
+
This module contains the core data models used for pagination, filtering, and sorting.
|
5
|
+
It defines the parameters that can be used to control pagination behavior and the
|
6
|
+
structure of pagination responses.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from collections.abc import Sequence
|
10
|
+
from enum import Enum
|
11
|
+
from typing import Any, Generic, TypeVar
|
12
|
+
|
13
|
+
from pydantic import BaseModel, ConfigDict, Field
|
14
|
+
|
15
|
+
T = TypeVar("T")
|
16
|
+
|
17
|
+
|
18
|
+
class SortOrder(str, Enum):
|
19
|
+
"""
|
20
|
+
Enumeration for sort order direction.
|
21
|
+
|
22
|
+
Attributes:
|
23
|
+
ASC: Ascending order (A to Z, 1 to 9)
|
24
|
+
DESC: Descending order (Z to A, 9 to 1)
|
25
|
+
"""
|
26
|
+
|
27
|
+
ASC = "asc"
|
28
|
+
DESC = "desc"
|
29
|
+
|
30
|
+
|
31
|
+
class FilterOperator(str, Enum):
|
32
|
+
"""
|
33
|
+
Enumeration for filter operations.
|
34
|
+
|
35
|
+
Attributes:
|
36
|
+
EQ: Equals (=)
|
37
|
+
NEQ: Not equals (!=)
|
38
|
+
GT: Greater than (>)
|
39
|
+
LT: Less than (<)
|
40
|
+
GTE: Greater than or equal (>=)
|
41
|
+
LTE: Less than or equal (<=)
|
42
|
+
LIKE: SQL LIKE pattern matching
|
43
|
+
ILIKE: Case-insensitive LIKE pattern matching
|
44
|
+
IN: Value in list
|
45
|
+
NOT_IN: Value not in list
|
46
|
+
"""
|
47
|
+
|
48
|
+
EQ = "eq" # equals
|
49
|
+
NEQ = "neq" # not equals
|
50
|
+
GT = "gt" # greater than
|
51
|
+
LT = "lt" # less than
|
52
|
+
GTE = "gte" # greater than or equal
|
53
|
+
LTE = "lte" # less than or equal
|
54
|
+
LIKE = "like" # LIKE operator
|
55
|
+
ILIKE = "ilike" # ILIKE operator
|
56
|
+
IN = "in" # IN operator
|
57
|
+
NOT_IN = "not_in" # NOT IN operator
|
58
|
+
|
59
|
+
|
60
|
+
class PaginationParams(BaseModel):
|
61
|
+
"""
|
62
|
+
Parameters for pagination, filtering, and sorting.
|
63
|
+
|
64
|
+
This model can be used directly as a FastAPI dependency to receive
|
65
|
+
pagination parameters from query strings.
|
66
|
+
|
67
|
+
Attributes:
|
68
|
+
page: Current page number (1-based)
|
69
|
+
page_size: Number of items per page
|
70
|
+
sort_by: Field name to sort by
|
71
|
+
sort_order: Sort direction (asc/desc)
|
72
|
+
filter_field: Field name to filter on
|
73
|
+
filter_operator: Filter operation to apply
|
74
|
+
filter_value: Value to filter by
|
75
|
+
"""
|
76
|
+
|
77
|
+
page: int = Field(default=1, gt=0)
|
78
|
+
page_size: int = Field(default=10, gt=0)
|
79
|
+
sort_by: str | None = None
|
80
|
+
sort_order: SortOrder = SortOrder.ASC
|
81
|
+
filter_field: str | None = None
|
82
|
+
filter_operator: FilterOperator | None = None
|
83
|
+
filter_value: Any | None = None
|
84
|
+
|
85
|
+
model_config = ConfigDict(from_attributes=True)
|
86
|
+
|
87
|
+
@property
|
88
|
+
def offset(self) -> int:
|
89
|
+
"""
|
90
|
+
Calculate the SQL offset for the current page.
|
91
|
+
|
92
|
+
Returns:
|
93
|
+
int: Number of items to skip
|
94
|
+
"""
|
95
|
+
return (self.page - 1) * self.page_size
|
96
|
+
|
97
|
+
|
98
|
+
class PageResponse(BaseModel, Generic[T]):
|
99
|
+
"""
|
100
|
+
Generic response model for paginated results.
|
101
|
+
|
102
|
+
Type parameter T represents the model type being paginated.
|
103
|
+
|
104
|
+
Attributes:
|
105
|
+
items: Sequence of items for the current page
|
106
|
+
total: Total number of items across all pages
|
107
|
+
page: Current page number
|
108
|
+
page_size: Number of items per page
|
109
|
+
pages: Total number of pages
|
110
|
+
has_next: Whether there is a next page
|
111
|
+
has_previous: Whether there is a previous page
|
112
|
+
"""
|
113
|
+
|
114
|
+
items: Sequence[T]
|
115
|
+
total: int
|
116
|
+
page: int
|
117
|
+
page_size: int
|
118
|
+
pages: int
|
119
|
+
has_next: bool
|
120
|
+
has_previous: bool
|
121
|
+
|
122
|
+
model_config = ConfigDict(from_attributes=True)
|