Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into upsert
Browse files Browse the repository at this point in the history
  • Loading branch information
dubusster committed May 14, 2024
2 parents 636218f + 8b23064 commit 6ac6319
Show file tree
Hide file tree
Showing 21 changed files with 1,403 additions and 199 deletions.
92 changes: 92 additions & 0 deletions docs/advanced/crud.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,51 @@

FastCRUD offers a flexible and powerful approach to handling CRUD operations in FastAPI applications, leveraging the SQLAlchemy ORM. Beyond basic CRUD functionality, FastCRUD provides advanced features like `allow_multiple` for updates and deletes, and support for advanced filters (e.g., less than, greater than). These features enable more complex and fine-grained data manipulation and querying capabilities.

## Typing Options for `FastCRUD`

Note that when initializing `FastCRUD`, assuming you have a model like:

```python
from sqlalchemy import Boolean, Column, DateTime, Integer, String
from sqlalchemy.orm import DeclarativeBase

class Base(DeclarativeBase):
pass

class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String)
archived = Column(Boolean, default=False)
archived_at = Column(DateTime)
```

You could just pass it to `FastCRUD`:

```python
from fastcrud import FastCRUD

crud_user = FastCRUD(User)
```

But you also may want a more robust typing, for that purpose, you may also pass the relevant pydantic schemas in the following way:

```python
from .models.user import User
from .schemas.user import UserCreate, UserUpdate, UserUpdateInternal, UserDelete

# Just pass None if you don't have one of the schemas
CRUDUser = FastCRUD[User, UserCreate, UserUpdate, UserUpdateInternal, UserDelete]
```

Then you can initialize CRUDUser like you would any FastCRUD instance, but with the relevant types:

```python
from .models.user import User

crud_user = CRUDUser(User)
```

## Allow Multiple Updates and Deletes

One of FastCRUD's advanced features is the ability to update or delete multiple records at once based on specified conditions. This is particularly useful for batch operations where you need to modify or remove several records that match certain criteria.
Expand Down Expand Up @@ -55,6 +100,15 @@ items = await item_crud.get_multi(
)
```

Currently supported filter operators are:
- __gt - greater than
- __lt - less than
- __gte - greater than or equal to
- __lte - less than or equal to
- __ne - not equal
- __in - included in (tuple, list or set)
- __not_in - not included in (tuple, list or set)

#### Counting Records

```python
Expand All @@ -65,6 +119,44 @@ item_count = await item_crud.count(
)
```

## Skipping Database Commit

For `create`, `update`, `db_delete` and `delete` methods of `FastCRUD`, you have the option of passing `commit=False` so you don't commit the operations immediately.

```python
from fastcrud import FastCRUD

from .models.item import Item
from .database import session as db

crud_items = FastCRUD(Item)

await crud_items.delete(
db=db,
commit=False,
id=1
)
# this will not actually delete until you run a db.commit()
```

## Unpaginated `get_multi` and `get_multi_joined`

If you pass `None` to `limit` in `get_multi` and `get_multi_joined`, you get the whole unpaginated set of data that matches the filters. Use this with caution.

```python
from fastcrud import FastCRUD

from .models.item import Item
from .database import session as db

crud_items = FastCRUD(Item)
items = await crud_items.get_multi(db=db, limit=None)
# this will return all items in the db
```

!!! CAUTION
Be cautious when returning all the data in your database, and you should almost never allow your API user to do this.

## Using `get_joined` and `get_multi_joined` for multiple models

To facilitate complex data relationships, `get_joined` and `get_multi_joined` can be configured to handle joins with multiple models. This is achieved using the `joins_config` parameter, where you can specify a list of `JoinConfig` instances, each representing a distinct join configuration.
Expand Down
76 changes: 75 additions & 1 deletion docs/advanced/joins.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,86 @@ For simpler join requirements, FastCRUD allows specifying join parameters direct
# Fetch tasks with user details, specifying a left join
tasks_with_users = await task_crud.get_joined(
db=db,
model=User,
join_model=User,
join_on=Task.user_id == User.id,
join_type="left"
)
```

#### Getting Joined Data Nested

Note that by default, `FastCRUD` joins all the data and returns it in a single dictionary.
Let's define two tables:
```python
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String)
tier_id = Column(Integer, ForeignKey("tier.id"))


class Tier(Base):
__tablename__ = "tier"
id = Column(Integer, primary_key=True)
name = Column(String, unique=True)
```

And join them with `FastCRUD`:

```python
user_tier = await user_crud.get_joined(
db=db,
join_model=Tier,
join_on=User.tier_id == Tier.id,
join_type="left",
join_prefix="tier_",,
id=1
)
```

We'll get:

```javascript
{
"id": 1,
"name": "Example",
"tier_id": 1,
"tier_name": "Free",
}
```

If you want the joined data in a nested dictionary instead, you may just pass `nest_joins=True`:

```python
user_tier = await user_crud.get_joined(
db=db,
join_model=Tier,
join_on=User.tier_id == Tier.id,
join_type="left",
join_prefix="tier_",
nest_joins=True,
id=1,
)
```

And you will get:

```javascript
{
"id": 1,
"name": "Example",
"tier": {
"id": 1,
"name": "Free",
},
}
```

This works for both `get_joined` and `get_multi_joined`.

!!! WARNING
Note that the final `"_"` in the passed `"tier_"` is stripped.

### Complex Joins Using `JoinConfig`

When dealing with more complex join conditions, such as multiple joins, self-referential joins, or needing to specify aliases and filters, `JoinConfig` instances become the norm. They offer granular control over each join's aspects, enabling precise and efficient data retrieval.
Expand Down
Loading

0 comments on commit 6ac6319

Please sign in to comment.