paginate-fastapi 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|