Skip to content

Commit

Permalink
Merge pull request #163 from igorbenav/preparations-for-0-15
Browse files Browse the repository at this point in the history
Preparations for `0.15.0`
  • Loading branch information
igorbenav authored Sep 18, 2024
2 parents d911dfb + d2f4a29 commit 7892520
Show file tree
Hide file tree
Showing 17 changed files with 265 additions and 331 deletions.
27 changes: 27 additions & 0 deletions docs/advanced/crud.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,33 @@ items = await item_crud.upsert_multi(
# this will return the upserted data in the form of ItemSchema
```

### Customizing the Update Logic

To allow more granular control over the SQL `UPDATE` operation during an upsert, `upsert_multi` can accept an `update_override` argument. This allows for the specification of custom update logic using SQL expressions, like the `case` statement, to handle complex conditions.

```python
from sqlalchemy.sql import case

update_override = {
"name": case(
(Item.name.is_(None), stmt.excluded.name),
else_=Item.name
)
}

items = await item_crud.upsert_multi(
db=db,
instances=[
CreateItemSchema(name="Gadget", price=15.99),
],
update_override=update_override,
schema_to_select=ItemSchema,
return_as_model=True,
)
```

In the example above, the `name` field of the `Item` model will be updated to the new value only if the existing `name` field is `None`. Otherwise, it retains the existing `name`.

#### Example: Joining `User`, `Tier`, and `Department` Models

Consider a scenario where you want to retrieve users along with their associated tier and department information. Here's how you can achieve this using `get_multi_joined`.
Expand Down
59 changes: 25 additions & 34 deletions docs/advanced/endpoint.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ FastCRUD automates the creation of CRUD (Create, Read, Update, Delete) endpoints

### Create

- **Endpoint**: `/create`
- **Endpoint**: `/{model}`
- **Method**: `POST`
- **Description**: Creates a new item in the database.
- **Request Body**: JSON object based on the `create_schema`.
- **Example Request**: `POST /items/create` with JSON body.
- **Example Request**: `POST /items` with JSON body.

### Read

- **Endpoint**: `/get/{id}`
- **Endpoint**: `/{model}/{id}`
- **Method**: `GET`
- **Description**: Retrieves a single item by its ID.
- **Path Parameters**: `id` - The ID of the item to retrieve.
- **Example Request**: `GET /items/get/1`.
- **Example Request**: `GET /items/1`.
- **Example Return**:
```javascript
{
Expand All @@ -33,13 +33,15 @@ FastCRUD automates the creation of CRUD (Create, Read, Update, Delete) endpoints

### Read Multiple

- **Endpoint**: `/get_multi`
- **Endpoint**: `/{model}`
- **Method**: `GET`
- **Description**: Retrieves multiple items with optional pagination.
- **Query Parameters**:
- `offset` (optional): The offset from where to start fetching items.
- `limit` (optional): The maximum number of items to return.
- **Example Request**: `GET /items/get_multi?offset=3&limit=4`.
- `page` (optional): The page number, starting from 1.
- `itemsPerPage` (optional): The number of items per page.
- **Example Request**: `GET /items?offset=3&limit=4`.
- **Example Return**:
```javascript
{
Expand Down Expand Up @@ -83,19 +85,9 @@ FastCRUD automates the creation of CRUD (Create, Read, Update, Delete) endpoints
],
"total_count": 50
}

```

### Read Paginated

- **Endpoint**: `/get_paginated`
- **Method**: `GET`
- **Description**: Retrieves multiple items with pagination.
- **Query Parameters**:
- `page`: The page number, starting from 1.
- `itemsPerPage`: The number of items per page.
- **Example Request**: `GET /items/get_paginated?page=1&itemsPerPage=3`.
- **Example Return**:
- **Example Paginated Request**: `GET /items?page=1&itemsPerPage=3`.
- **Example Paginated Return**:
```javascript
{
"data": [
Expand Down Expand Up @@ -134,48 +126,48 @@ FastCRUD automates the creation of CRUD (Create, Read, Update, Delete) endpoints
}
```

!!! WARNING
!!! NOTE

`_read_paginated` endpoint is getting deprecated and mixed into `_read_items` in the next major release.
Please use `_read_items` with optional `page` and `items_per_page` query params instead, to achieve pagination as before.
`_read_paginated` endpoint was deprecated and mixed into `_read_items` in the release `0.15.0`.
Simple `_read_items` behaviour persists with no breaking changes.

Read items paginated:
```sh
$ curl -X 'GET' \
'http://localhost:8000/users/get_multi?page=2&itemsPerPage=10' \
'http://localhost:8000/users?page=2&itemsPerPage=10' \
-H 'accept: application/json'
```

Read items unpaginated:
```sh
$ curl -X 'GET' \
'http://localhost:8000/users/get_multi?offset=0&limit=100' \
'http://localhost:8000/users?offset=0&limit=100' \
-H 'accept: application/json'
```


### Update

- **Endpoint**: `/update/{id}`
- **Endpoint**: `/{model}/{id}`
- **Method**: `PATCH`
- **Description**: Updates an existing item by its ID.
- **Path Parameters**: `id` - The ID of the item to update.
- **Request Body**: JSON object based on the `update_schema`.
- **Example Request**: `PATCH /items/update/1` with JSON body.
- **Example Request**: `PATCH /items/1` with JSON body.
- **Example Return**: `None`

### Delete

- **Endpoint**: `/delete/{id}`
- **Endpoint**: `/{model}/{id}`
- **Method**: `DELETE`
- **Description**: Deletes (soft delete if configured) an item by its ID.
- **Path Parameters**: `id` - The ID of the item to delete.
- **Example Request**: `DELETE /items/delete/1`.
- **Example Request**: `DELETE /items/1`.
- **Example Return**: `None`

### DB Delete (Hard Delete)

- **Endpoint**: `/db_delete/{id}` (Available if a `delete_schema` is provided)
- **Endpoint**: `/{model}/db_delete/{id}` (Available if a `delete_schema` is provided)
- **Method**: `DELETE`
- **Description**: Permanently deletes an item by its ID, bypassing the soft delete mechanism.
- **Path Parameters**: `id` - The ID of the item to hard delete.
Expand Down Expand Up @@ -251,7 +243,7 @@ app.include_router(my_router)

## Customizing Endpoint Names

You can customize the names of the auto generated endpoints by passing an `endpoint_names` dictionary when initializing the `EndpointCreator` or calling the `crud_router` function. This dictionary should map the CRUD operation names (`create`, `read`, `update`, `delete`, `db_delete`, `read_multi`, `read_paginated`) to your desired endpoint names.
You can customize the names of the auto generated endpoints by passing an `endpoint_names` dictionary when initializing the `EndpointCreator` or calling the `crud_router` function. This dictionary should map the CRUD operation names (`create`, `read`, `update`, `delete`, `db_delete`, `read_multi`) to your desired endpoint names.

### Example: Using `crud_router`

Expand All @@ -274,7 +266,6 @@ custom_endpoint_names = {
"update": "modify",
"delete": "remove",
"read_multi": "list",
"read_paginated": "paginate",
}

# Setup CRUD router with custom endpoint names
Expand Down Expand Up @@ -326,9 +317,9 @@ app.include_router(endpoint_creator.router)

You only need to pass the names of the endpoints you want to change in the `endpoint_names` `dict`.

!!! WARNING
!!! NOTE

`default_endpoint_names` for `EndpointCreator` are going to be changed to empty strings in the next major release.
`default_endpoint_names` for `EndpointCreator` were changed to empty strings in `0.15.0`.
See [this issue](https://github.com/igorbenav/fastcrud/issues/67) for more details.

## Extending `EndpointCreator`
Expand Down Expand Up @@ -551,7 +542,7 @@ app.include_router(endpoint_creator(

## Using Filters in FastCRUD

FastCRUD provides filtering capabilities, allowing you to filter query results based on various conditions. Filters can be applied to `read_multi` and `read_paginated` endpoints. This section explains how to configure and use filters in FastCRUD.
FastCRUD provides filtering capabilities, allowing you to filter query results based on various conditions. Filters can be applied to `read_multi` endpoint. This section explains how to configure and use filters in FastCRUD.

### Defining Filters

Expand Down Expand Up @@ -607,7 +598,7 @@ app.include_router(
Once filters are configured, you can use them in your API requests. Filters are passed as query parameters. Here's an example of how to use filters in a request to a paginated endpoint:

```http
GET /yourmodel/get_paginated?page=1&itemsPerPage=3&tier_id=1&name=Alice
GET /yourmodel?page=1&itemsPerPage=3&tier_id=1&name=Alice
```

### Custom Filter Validation
Expand Down
8 changes: 2 additions & 6 deletions fastcrud/endpoint/crud_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ def crud_router(
create_deps: Sequence[Callable] = [],
read_deps: Sequence[Callable] = [],
read_multi_deps: Sequence[Callable] = [],
read_paginated_deps: Sequence[Callable] = [],
update_deps: Sequence[Callable] = [],
delete_deps: Sequence[Callable] = [],
db_delete_deps: Sequence[Callable] = [],
Expand Down Expand Up @@ -60,7 +59,6 @@ def crud_router(
create_deps: Optional list of functions to be injected as dependencies for the create endpoint.
read_deps: Optional list of functions to be injected as dependencies for the read endpoint.
read_multi_deps: Optional list of functions to be injected as dependencies for the read multiple items endpoint.
read_paginated_deps: Optional list of functions to be injected as dependencies for the read paginated endpoint.
update_deps: Optional list of functions to be injected as dependencies for the update endpoint.
delete_deps: Optional list of functions to be injected as dependencies for the delete endpoint.
db_delete_deps: Optional list of functions to be injected as dependencies for the hard delete endpoint.
Expand All @@ -71,9 +69,9 @@ def crud_router(
deleted_at_column: Optional column name to use for storing the timestamp of a soft delete. Defaults to `"deleted_at"`.
updated_at_column: Optional column name to use for storing the timestamp of an update. Defaults to `"updated_at"`.
endpoint_names: Optional dictionary to customize endpoint names for CRUD operations. Keys are operation types
(`"create"`, `"read"`, `"update"`, `"delete"`, `"db_delete"`, `"read_multi"`, `"read_paginated"`), and
(`"create"`, `"read"`, `"update"`, `"delete"`, `"db_delete"`, `"read_multi"`), and
values are the custom names to use. Unspecified operations will use default names.
filter_config: Optional `FilterConfig` instance or dictionary to configure filters for the `read_multi` and `read_paginated` endpoints.
filter_config: Optional `FilterConfig` instance or dictionary to configure filters for the `read_multi` endpoint.
Returns:
Configured `APIRouter` instance with the CRUD endpoints.
Expand Down Expand Up @@ -457,7 +455,6 @@ async def add_routes_to_router(self, ...):
"delete": "remove_task",
"db_delete": "permanently_remove_task",
"read_multi": "list_tasks",
"read_paginated": "paginate_tasks",
},
)
```
Expand Down Expand Up @@ -550,7 +547,6 @@ async def add_routes_to_router(self, ...):
create_deps=create_deps,
read_deps=read_deps,
read_multi_deps=read_multi_deps,
read_paginated_deps=read_paginated_deps,
update_deps=update_deps,
delete_deps=delete_deps,
db_delete_deps=db_delete_deps,
Expand Down
Loading

0 comments on commit 7892520

Please sign in to comment.