Skip to content

Commit

Permalink
Merge pull request #3 from so-saf/expand_docs
Browse files Browse the repository at this point in the history
📝 Expand documentation
  • Loading branch information
so-saf authored Sep 29, 2024
2 parents ddc73e2 + 7f726cf commit b19415c
Show file tree
Hide file tree
Showing 39 changed files with 1,983 additions and 81 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/build-docs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Build Documentation

on:
push:
branches:
- master

permissions:
contents: write

env:
DEFAULT_PYTHON: "3.12"

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure Git Credentials
run: |
git config user.name github-actions[bot]
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
- name: Set up Poetry
run: pipx install poetry
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@v5
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache: "poetry"
- name: Install workflow dependencies
run: |
poetry config virtualenvs.create true
poetry config virtualenvs.in-project true
- name: Install dependencies
run: poetry install --no-interaction
- run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
key: mkdocs-material-${{ env.cache_id }}
path: .cache
restore-keys: |
mkdocs-material-
- run: cd docs
- run: mkdocs gh-deploy --force
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,29 @@
[![license](https://img.shields.io/github/license/so-saf/pydantic-filters.svg)](https://github.com/so-saf/pydantic-filters/blob/main/LICENSE)
[![versions](https://img.shields.io/pypi/pyversions/pydantic-filters.svg)](https://github.com/so-saf/pydantic-filters)

**Documentation:** https://so-saf.github.io/pydantic-filters/

**Source Code:** https://github.com/so-saf/pydantic-filters

---

Describe the filters, not implement them!
A declarative and intuitive way to describe data filtering and sorting in your application.

The only required dependency is Pydantic.
You can use the basic features without being attached to specific frameworks,
or use one of the supported plugins and drivers:

Plugins:
* FastAPI >= 0.100.0
# Features

Drivers:
* SQLAlchemy >= 2
- Filtering by the models themselves as well as by related.
- Built-in pagination and sorting.
- Lots of settings and possible customizations.
- The only required dependency is Pydantic.
You can use the basic features without being attached to specific frameworks,
or use one of the supported plugins and drivers:
- Plugins:
- FastAPI >= 0.100.0
- Drivers:
- SQLAlchemy >= 2

## Installation
# Installation

```shell
pip install pydantic-filters
Expand Down Expand Up @@ -113,6 +118,4 @@ app = FastAPI(title="User Service")
app.include_router(router, prefix="/users", tags=["User"])
```

![fastapi-simple-example.png](docs/statics/fastapi-simple-example.png)

# API Reference
![fastapi-simple-example.png](docs/docs/images/fastapi-simple-example.png)
11 changes: 11 additions & 0 deletions docs/docs/api/drivers/sqlalchemy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@


::: pydantic_filters.drivers.sqlalchemy.append_filter_to_statement
::: pydantic_filters.drivers.sqlalchemy.append_pagination_to_statement
::: pydantic_filters.drivers.sqlalchemy.append_sort_to_statement
::: pydantic_filters.drivers.sqlalchemy.append_to_statement
::: pydantic_filters.drivers.sqlalchemy.get_count_statement
::: pydantic_filters.drivers.sqlalchemy.BaseSaDriverError
::: pydantic_filters.drivers.sqlalchemy.AttributeNotFoundSaDriverError
::: pydantic_filters.drivers.sqlalchemy.RelationshipNotFoundSaDriverError
::: pydantic_filters.drivers.sqlalchemy.SupportSaDriverError
2 changes: 2 additions & 0 deletions docs/docs/api/filter/base_filter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

::: pydantic_filters.BaseFilter
2 changes: 2 additions & 0 deletions docs/docs/api/filter/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

::: pydantic_filters.FilterConfigDict
12 changes: 12 additions & 0 deletions docs/docs/api/filter/fields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

::: pydantic_filters.FilterField

::: pydantic_filters.SearchField

::: pydantic_filters.filter._fields.FilterFieldInfo
options:
inherited_members: true

::: pydantic_filters.filter._fields.SearchFieldInfo
options:
inherited_members: true
7 changes: 7 additions & 0 deletions docs/docs/api/filter/types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

::: pydantic_filters.FilterType
::: pydantic_filters.filter.FilterTypeLiteral
::: pydantic_filters.SearchType
::: pydantic_filters.filter.SearchTypeLiteral
::: pydantic_filters.filter._types._suffixes_map
::: pydantic_filters.get_suffixes_map
10 changes: 10 additions & 0 deletions docs/docs/api/pagination/pagination.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

::: pydantic_filters.BasePagination

::: pydantic_filters.OffsetPagination
options:
inherited_members: true

::: pydantic_filters.PagePagination
options:
inherited_members: true
4 changes: 4 additions & 0 deletions docs/docs/api/plugins/fastapi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

::: pydantic_filters.plugins.fastapi.FilterDepends
::: pydantic_filters.plugins.fastapi.PaginationDepends
::: pydantic_filters.plugins.fastapi.SortDepends
4 changes: 4 additions & 0 deletions docs/docs/api/sorting/sorting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

::: pydantic_filters.BaseSort

::: pydantic_filters.SortByOrder
Binary file added docs/docs/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/docs/images/fastapi-simple-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
124 changes: 124 additions & 0 deletions docs/docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
---
hide:
- navigation
- toc
---


# pydantic-filters

[![Testing](https://github.com/so-saf/pydantic-filters/actions/workflows/test.yaml/badge.svg)](https://github.com/so-saf/pydantic-filters/actions/workflows/test.yaml)
[![pypi](https://img.shields.io/pypi/v/pydantic-filters.svg)](https://pypi.python.org/pypi/pydantic-filters)
[![license](https://img.shields.io/github/license/so-saf/pydantic-filters.svg)](https://github.com/so-saf/pydantic-filters/blob/main/LICENSE)
[![versions](https://img.shields.io/pypi/pyversions/pydantic-filters.svg)](https://github.com/so-saf/pydantic-filters)

**Source Code:** [https://github.com/so-saf/pydantic-filters](https://github.com/so-saf/pydantic-filters)

---

Describe the filters, not implement them!
A declarative and intuitive way to describe data filtering and sorting in your application.

# Features

- Filtering by the models themselves as well as by related.
- Built-in pagination and sorting.
- Lots of settings and possible customizations.
- The only required dependency is Pydantic.
You can use the basic features without being attached to specific frameworks,
or use one of the supported plugins and drivers:
- Plugins:
- FastAPI >= 0.100.0
- Drivers:
- SQLAlchemy >= 2

# Installation

```shell
pip install pydantic-filters
```

# A Simple Example

`BaseFilter` is just a pydantic model, it should be treated similarly

Let's imagine you have a simple user service with the following SQLAlchemy model:


```python
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column


class Base(DeclarativeBase):
pass


class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
age: Mapped[int]
```

Describe how you would like to filter users using BaseFilter.

```python
from typing import List
from pydantic_filters import BaseFilter


class UserFilter(BaseFilter):
id: List[int]
name: List[str]
name__ilike: str
age__lt: int
age__gt: int
```

`BaseFilter` is just a pydantic model, it should be treated similarly

Next, you need to apply a filter to some query:

```python
from sqlalchemy import select
from pydantic_filters.drivers.sqlalchemy import append_filter_to_statement

statement = select(User)
filter_ = UserFilter(name__ilike="kate", age__lt=23)

stmt = append_filter_to_statement(
statement=statement, model=User, filter_=filter_,
)
```

And get something like:

```sql
SELECT users.id, users.name, users.age
FROM users
WHERE users.name ILIKE 'kate' AND users.age < 23
```

The filter can be used in conjunction with one of the supported web frameworks:

```python
from typing import Annotated
from fastapi import FastAPI, APIRouter
from pydantic_filters.plugins.fastapi import FilterDepends


router = APIRouter()


@router.get("/")
async def get_multiple(
filter_: Annotated[UserFilter, FilterDepends(UserFilter)],
):
...


app = FastAPI(title="User Service")
app.include_router(router, prefix="/users", tags=["User"])
```

![fastapi-simple-example.png](images/fastapi-simple-example.png)
1 change: 1 addition & 0 deletions docs/docs/logo-white.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 63 additions & 0 deletions docs/docs/usage/fastapi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

`FastAPI` is a modern and fast web framework for Python.

`pydantic-filters` provides several features for integrations:
[`FilterDepends`][pydantic_filters.plugins.fastapi.FilterDepends],
[`PaginationDepends`][pydantic_filters.plugins.fastapi.PaginationDepends] and
[`SortDepends`][pydantic_filters.plugins.fastapi.SortDepends].
Each of the functions unpacks the pydantic model and convert `pydantic.FieldInfo`
fields to `fastapi.Query`.

## Example

```python
from enum import Enum
from typing import List, Optional

from fastapi import FastAPI
from pydantic_filters import BaseFilter, BaseSort, FilterField, OffsetPagination, SearchField
from pydantic_filters.plugins.fastapi import FilterDepends, PaginationDepends, SortDepends


class DepartmentFilter(BaseFilter):
chef_id: List[int] = FilterField(description="Here is the related field!!!")


class UserFilter(BaseFilter):
login: List[str]
age__lt: int = FilterField(gt=0, le=100)
q: str = SearchField(target=["login", "name", "email"])
# Related filter!
department: DepartmentFilter


class UserSortByEnum(str, Enum):
id = "id"
login = "login"
age = "age"


class UserSort(BaseSort):
sort_by: Optional[UserSortByEnum] = None


app = FastAPI()


@app.get("/users")
async def get_multiple_users(
filter_: UserFilter = FilterDepends(UserFilter),
pagination: OffsetPagination = PaginationDepends(OffsetPagination),
sort: UserSort = SortDepends(UserSort),
):
...
```

!!! Tip

As of [`FastAPI>=0.115`](https://github.com/fastapi/fastapi/releases/tag/0.115.0),
the [`PaginationDepends`][pydantic_filters.plugins.fastapi.PaginationDepends] and
[`SortDepends`][pydantic_filters.plugins.fastapi.SortDepends] functions can be replaced by
`Annotated[PaginationOrSortSchema, fastapi.Query()]`.

![fastapi-not-so-simple-example.png](../images/fastapi-not-so-simple-example.png)
Loading

0 comments on commit b19415c

Please sign in to comment.