Skip to content

Commit 4fbe049

Browse files
authored
Merge pull request #167 from uriyyo/feature/piccolo-integration
🔧 Add piccolo integration
2 parents eee5f46 + 44d4f49 commit 4fbe049

File tree

6 files changed

+575
-263
lines changed

6 files changed

+575
-263
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Available integrations:
2626
* [orm](https://github.com/encode/orm)
2727
* [tortoise](https://github.com/tortoise/tortoise-orm)
2828
* [django](https://github.com/django/django)
29+
* [piccolo](https://github.com/piccolo-orm/piccolo)
2930

3031
## Example
3132

examples/pagination_piccolo.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import os
2+
from itertools import count
3+
from pathlib import Path
4+
from typing import Any
5+
6+
import uvicorn
7+
from faker import Faker
8+
from fastapi import FastAPI
9+
from piccolo.columns import Integer, Text
10+
from piccolo.conf.apps import AppConfig, AppRegistry
11+
from piccolo.engine import SQLiteEngine, engine_finder
12+
from piccolo.table import Table
13+
from pydantic import BaseModel
14+
15+
from fastapi_pagination import LimitOffsetPage, Page, add_pagination
16+
from fastapi_pagination.ext.piccolo import paginate
17+
18+
os.environ["PICCOLO_CONF"] = __name__
19+
20+
_counter = count().__next__
21+
22+
faker = Faker()
23+
24+
25+
class _User(Table):
26+
id = Integer(default=_counter, primary_key=True)
27+
name = Text(required=False, null=True)
28+
email = Text(required=False, null=True)
29+
30+
31+
class UserIn(BaseModel):
32+
name: str
33+
email: str
34+
35+
36+
class UserOut(UserIn):
37+
id: int
38+
39+
class Config:
40+
orm_mode = True
41+
42+
43+
app = FastAPI()
44+
45+
DB = SQLiteEngine()
46+
APP_REGISTRY = AppRegistry()
47+
48+
APP_CONFIG = AppConfig(
49+
app_name="example",
50+
migrations_folder_path=None,
51+
table_classes=[_User],
52+
)
53+
54+
55+
@app.on_event("startup")
56+
async def on_startup() -> None:
57+
engine: SQLiteEngine = engine_finder()
58+
59+
p = Path(engine.path)
60+
if p.exists():
61+
os.remove(p)
62+
63+
await engine.prep_database()
64+
await _User.create_table().run()
65+
66+
for _ in range(100):
67+
await _User(
68+
name=faker.name(),
69+
email=faker.email(),
70+
).save()
71+
72+
73+
@app.post("/users", response_model=UserOut)
74+
async def create_user(user_in: UserIn) -> Any:
75+
return await _User(**user_in.dict()).save()
76+
77+
78+
@app.get("/users/default", response_model=Page[UserOut])
79+
@app.get("/users/limit-offset", response_model=LimitOffsetPage[UserOut])
80+
async def get_users() -> Any:
81+
return await paginate(_User)
82+
83+
84+
add_pagination(app)
85+
86+
if __name__ == "__main__":
87+
uvicorn.run("pagination_piccolo:app")

fastapi_pagination/ext/piccolo.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from copy import deepcopy
2+
from typing import Optional, Type, Union
3+
4+
from piccolo.query import Select
5+
from piccolo.query.methods.select import Count
6+
from piccolo.table import Table
7+
8+
from ..api import create_page, resolve_params
9+
from ..bases import AbstractPage, AbstractParams
10+
11+
12+
async def paginate(query: Union[Select, Type[Table]], params: Optional[AbstractParams] = None) -> AbstractPage:
13+
if not isinstance(query, Select):
14+
query = query.select()
15+
16+
# query object is mutable, so we need deepcopy of it
17+
query = deepcopy(query)
18+
19+
params = resolve_params(params)
20+
raw_params = params.to_raw_params()
21+
22+
# need another copy for count query
23+
count_query = deepcopy(query)
24+
count_query.columns_delegate.selected_columns.clear()
25+
26+
total = (await count_query.columns(Count()).first())["count"]
27+
items = await query.offset(raw_params.offset).limit(raw_params.limit)
28+
29+
return create_page(items, total, params)
30+
31+
32+
__all__ = ["paginate"]

0 commit comments

Comments
 (0)