Fastcrud

Latest version: v0.15.1

Safety actively analyzes 681812 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 1 of 4

0.15.1

Added
- **Support for fastapi >=0.100**

What's Changed
* now supporting fastapi >= 0.100.0 by igorbenav in https://github.com/igorbenav/fastcrud/pull/166

**Full Changelog**: https://github.com/igorbenav/fastcrud/compare/v0.15.0...v0.15.1
___

0.15.0

Added
- **Models and Schemas for Task Management (Batch 3)** by [slaarti](https://github.com/slaarti)
- **Models and Schemas for Articles, Authors, and Profiles (Batch 4)** by [slaarti](https://github.com/slaarti)
- **`update_override` Argument to `upsert_multi` Method** by [feluelle](https://github.com/feluelle)
- **Configurable `is_deleted` Field in Soft Delete Logic** by [gal-dahan](https://github.com/gal-dahan)

Improved
- **Fixed Complex Parameter Filter with `between` Operator** by [wu-clan](https://github.com/wu-clan)
- **Fixed Cryptography Package Vulnerability**
- **Resolved Update Column Name Collision in Update Method**

Fixed
- **Vulnerability in `cryptography` Package** updated to `cryptography = "^43.0.1"`
- **Update Column Name Collision** in the `update` method

Documentation Updates
- **Added Documentation for New Models and Schemas** by [slaarti](https://github.com/slaarti)
- **Updated `upsert_multi` Method Documentation with `update_override` Usage** by [feluelle](https://github.com/feluelle)
- **Clarified Endpoint Simplification and Deprecation Notices**

Warnings
- **Deprecation Notice**: The `_read_paginated` endpoint has been removed. Please transition to using `_read_items` with pagination parameters. [Docs here](https://igorbenav.github.io/fastcrud/advanced/endpoint/#read-multiple).
- **Deprecation Notice**: Handling of `Depends` is now only callable within `_inject_depend`. Update your code accordingly.
- **Configuration Change Alert**: Endpoints are simplified by default. Adjust your configurations to align with the new defaults. [Docs here](https://igorbenav.github.io/fastcrud/advanced/endpoint/#available-automatic-endpoints).

___
Detailed Changes

Endpoint Simplification and Deprecation of `_read_paginated`

Description

To streamline API endpoint configurations, endpoints with empty strings as names are now the standard. Additionally, the `_read_paginated` endpoint has been removed, with its functionality merged into `_read_items`.

Changes

- **Simplified Endpoint Configuration**: Endpoints can now be defined with empty strings to create cleaner paths.
- **Removed `_read_paginated` Endpoint**: Pagination is now handled via optional parameters in `_read_items`.

Usage Examples

**Paginated Read Example:**

bash
curl -X 'GET' \
'http://localhost:8000/items?page=2&itemsPerPage=10' \
-H 'accept: application/json'


**Non-Paginated Read Example:**

bash
curl -X 'GET' \
'http://localhost:8000/items?offset=0&limit=100' \
-H 'accept: application/json'



Warnings

!!! WARNING
The `_read_paginated` endpoint is deprecated. Use `_read_items` with pagination parameters instead.

!!! WARNING
Default endpoint names are now empty strings. Adjust your configurations to match the new defaults.

___

`update_override` Argument in `upsert_multi` Method

Description

The `upsert_multi` method now includes an `update_override` argument, giving developers the ability to override the default update logic during upsert operations. This enhancement provides greater flexibility for custom update scenarios, such as utilizing SQL `CASE` statements or other complex expressions.

Changes

- **`update_override` Argument**: Allows custom update logic in `upsert_multi`.
- **Dialect Support**: Implemented for PostgreSQL, SQLite, and MySQL.
- **Tests**: Added comprehensive tests to ensure functionality across different SQL dialects.

Usage Example

python
from fastcrud import FastCRUD
from sqlalchemy import case
from .models.item import Item
from .database import session as db

crud_items = FastCRUD(Item)

await crud_items.upsert_multi(
db=db,
instances=[
ItemCreateSchema(id=1, name="Item A", price=10),
ItemCreateSchema(id=2, name="Item B", price=20),
],
update_override={
"price": case(
(Item.price.is_(None), db.excluded.price),
else_=Item.price,
)
}
)


___

Configurable `is_deleted` Field in Soft Delete Logic

Description

The `is_deleted` field in the soft delete logic is now optional and configurable. This change allows developers to customize the soft delete behavior per model, providing flexibility in how deletion states are handled.

___

New Contributors
- [wu-clan](https://github.com/wu-clan) made their first contribution 🌟
- [gal-dahan](https://github.com/gal-dahan) made their first contribution 🌟

**Full Changelog**: [View the full changelog](https://github.com/igorbenav/fastcrud/compare/v0.14.0...v0.15.0)
___

0.14.0

Added
- Type-checking support for SQLModel types by kdcokenny πŸš€
- Returning clause to update operations by feluelle
- Upsert_multi functionality by feluelle
- Simplified endpoint configurations by JakNowy, streamlining path generation and merging pagination functionalities into a unified `_read_items` endpoint, promoting more efficient API structure and usage. Details in https://github.com/igorbenav/fastcrud/pull/105

Improved
- Comprehensive tests for paginated retrieval of items, maintaining 100% coverage
- Docker client check before running tests that require Docker by feluelle

Fixed
- Vulnerability associated with an outdated cryptography package
- Return type inconsistency in async session fixtures by slaarti

Documentation Updates
- Cleanup of documentation formatting by slaarti
- Replacement of the Contributing section in docs with an include to file in repo root by slaarti
- Correction of links to advanced filters in docstrings by slaarti
- Backfill of docstring fixes across various modules by slaarti
- Enhanced filter documentation with new AND and OR clause examples, making complex queries more accessible and understandable.

Models and Schemas Enhancements
- Introduction of simple and one-off models (Batch 1) by slaarti
- Expansion to include models and schemas for Customers, Products, and Orders (Batch 2) by slaarti

Code Refinements
- Resolution of missing type specifications in kwargs by slaarti
- Collapsed space adjustments for models/schemas in `fast_crud.py` by slaarti

Warnings
- **Deprecation Notice**: `_read_paginated` endpoint is set to be deprecated and merged into `_read_items`. Users are encouraged to transition to the latter, utilizing optional pagination parameters. Full details and usage instructions provided to ensure a smooth transition.
- **Future Changes Alert**: Default endpoint names in `EndpointCreator` are anticipated to be set to empty strings in a forthcoming major release, aligning with simplification efforts. Refer to https://github.com/igorbenav/fastcrud/issues/67 for more information.

___
Detailed Changes

Simplified Endpoint Configurations

In an effort to streamline FastCRUD’s API, we have reconfigured endpoint paths to avoid redundancy (great work by JakNowy). This change allows developers to specify empty strings for endpoint names in the `crud_router` setup, which prevents the generation of unnecessary `//` in the paths. The following configurations illustrate how endpoints can now be defined more succinctly:

python
endpoint_names = {
"create": "",
"read": "",
"update": "",
"delete": "",
"db_delete": "",
"read_multi": "",
"read_paginated": "get_paginated",
}


Moreover, the `_read_paginated` logic has been integrated into the `_read_items` endpoint. This integration means that pagination can now be controlled via `page` and `items_per_page` query parameters, offering a unified method for both paginated and non-paginated reads:

- **Paginated read example**:

bash
curl -X 'GET' \
'http://localhost:8000/users/get_multi?page=2&itemsPerPage=10' \
-H 'accept: application/json'


- **Non-paginated read example**:

bash
curl -X 'GET' \
'http://localhost:8000/users/get_multi?offset=0&limit=100' \
-H 'accept: application/json'


Warnings

- **Deprecation Warning**: The `_read_paginated` endpoint is slated for deprecation. Developers should transition to using `_read_items` with the relevant pagination parameters.
- **Configuration Change Alert**: In a future major release, default endpoint names in `EndpointCreator` will be empty strings by default, as discussed in [Issue 67](https://github.com/igorbenav/fastcrud/issues/67).

Advanced Filters Documentation Update

Documentation for advanced filters has been expanded to include comprehensive examples of AND and OR clauses, enhancing the utility and accessibility of complex query constructions.

- **OR clause example**:

python
Fetch items priced under $5 or above $20
items = await item_crud.get_multi(
db=db,
price__or={'lt': 5, 'gt': 20},
)


- **AND clause example**:

python
Fetch items priced under $20 and over 2 years of warranty
items = await item_crud.get_multi(
db=db,
price__lt=20,
warranty_years__gt=2,
)


___
Returning Clauses in Update Operations

Description
Users can now retrieve updated records immediately following an update operation. This feature streamlines the process, reducing the need for subsequent retrieval calls and increasing efficiency.

Changes
- **Return Columns**: Specify the columns to be returned after the update via the `return_columns` argument.
- **Schema Selection**: Optionally select a Pydantic schema to format the returned data using the `schema_to_select` argument.
- **Return as Model**: Decide if the returned data should be converted into a model using the `return_as_model` argument.
- **Single or None**: Utilize the `one_or_none` argument to ensure that either a single record is returned or none, in case the conditions do not match any records.

These additions are aligned with existing CRUD API functions, enhancing consistency across the library and making the new features intuitive for users.

Usage Example

Returning Updated Fields

python
from fastcrud import FastCRUD
from .models.item import Item
from .database import session as db

crud_items = FastCRUD(Item)
updated_item = await crud_items.update(
db=db,
object={"price": 9.99},
price__lt=10,
return_columns=["price"]
)
This returns the updated price of the item directly.


Returning Data as a Model

python
from fastcrud import FastCRUD
from .models.item import Item
from .schemas.item import ItemSchema
from .database import session as db

crud_items = FastCRUD(Item)
updated_item_schema = await crud_items.update(
db=db,
object={"price": 9.99},
price__lt=10,
schema_to_select=ItemSchema,
return_as_model=True
)
This returns the updated item data formatted as an ItemSchema model.


___
Bulk Upsert Operations with `upsert_multi`

The `upsert_multi` method provides the ability to perform bulk upsert operations, which are optimized for different SQL dialects.

Changes
- **Dialect-Optimized SQL**: Uses the most efficient SQL commands based on the database's SQL dialect.
- **Support for Multiple Dialects**: Includes custom implementations for PostgreSQL, SQLite, and MySQL, with appropriate handling for each's capabilities and limitations.

Usage Example

Upserting Multiple Records

python
from fastcrud import FastCRUD
from .models.item import Item
from .schemas.item import ItemCreateSchema, ItemSchema
from .database import session as db

crud_items = FastCRUD(Item)
items = await crud_items.upsert_multi(
db=db,
instances=[
ItemCreateSchema(price=9.99),
],
schema_to_select=ItemSchema,
return_as_model=True,
)
This will return the upserted data in the form of ItemSchema.


Implementation Details

`upsert_multi` handles different database dialects:
- **PostgreSQL**: Uses `ON CONFLICT DO UPDATE`.
- **SQLite**: Utilizes `ON CONFLICT DO UPDATE`.
- **MySQL**: Implements `ON DUPLICATE KEY UPDATE`.

Notes
- MySQL and MariaDB do not support certain advanced features used in other dialects, such as returning values directly after an insert or update operation. This limitation is clearly documented to prevent misuse.

New Contributors
- kdcokenny made their first contribution 🌟
- feluelle made their first contribution 🌟

**Full Changelog**: [View the full changelog](https://github.com/igorbenav/fastcrud/compare/v0.13.1...v0.14.0)

0.13.1

Added
- More Advanced Filters by JakNowy πŸŽ‰

Fixed
- Bug where objects with null primary key are returned with all fields set to None in nested joins 102

___
Detailed Changes

Advanced Filters

FastCRUD supports advanced filtering options, allowing you to query records using operators such as greater than (`__gt`), less than (`__lt`), and their inclusive counterparts (`__gte`, `__lte`). These filters can be used in any method that retrieves or operates on records, including `get`, `get_multi`, `exists`, `count`, `update`, and `delete`.

Single parameter filters

Most filter operators require a single string or integer value.

python
Fetch items priced above $5
items = await item_crud.get_multi(
db=db,
price__gte=5,
)


Currently supported single parameter filters are:
- __gt - greater than
- __lt - less than
- __gte - greater than or equal to
- __lte - less than or equal to
- __ne - not equal
- __is - used to test True, False, and None identity
- __is_not - negation of "is"
- __like - SQL "like" search for specific text pattern
- __notlike - negation of "like"
- __ilike - case insensitive "like"
- __notilike - case insensitive "notlike"
- __startswith - text starts with given string
- __endswith - text ends with given string
- __contains - text contains given string
- __match - database-specific match expression

Complex parameter filters

Some operators require multiple values. They must be passed as a python tuple, list, or set.

python
Fetch items priced between $5 and $20
items = await item_crud.get_multi(
db=db,
price__between=(5, 20),
)

- __between - between 2 numeric values
- __in - included in
- __not_in - not included in

OR parameter filters

More complex OR filters are supported. They must be passed as a dictionary, where each key is a library-supported operator to be used in OR expression and values are what get's passed as the parameter.

python
Fetch items priced under $5 or above $20
items = await item_crud.get_multi(
db=db,
price__or={'lt': 5, 'gt': 20},
)


What's Changed
- Missing sqlalchemy operators by [JakNowy](https://github.com/JakNowy) in https://github.com/igorbenav/fastcrud/pull/85
- Null primary key bug fixed in https://github.com/igorbenav/fastcrud/pull/107

**Full Changelog**: https://github.com/igorbenav/fastcrud/compare/v0.13.0...v0.13.1

0.13.0

Added
- Filters in Automatic Endpoints πŸŽ‰
- One-to-many support in joins
- Upsert method in FastCRUD class by dubusster

___
Detailed Changes

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.


Defining Filters

Filters are either defined using the `FilterConfig` class or just passed as a dictionary. This class allows you to specify default filter values and validate filter types. Here's an example of how to define filters for a model:

python
from fastcrud import FilterConfig

Define filter configuration for a model
filter_config = FilterConfig(
tier_id=None, Default filter value for tier_id
name=None Default filter value for name
)


And the same thing using a `dict`:
python
filter_config = {
"tier_id": None, Default filter value for tier_id
"name": None, Default filter value for name
}


By using `FilterConfig` you get better error messages.

Applying Filters to Endpoints

You can apply filters to your endpoints by passing the `filter_config` to the `crud_router` or `EndpointCreator`. Here's an example:

python
from fastcrud import crud_router
from yourapp.models import YourModel
from yourapp.schemas import CreateYourModelSchema, UpdateYourModelSchema
from yourapp.database import async_session

Apply filters using crud_router
app.include_router(
crud_router(
session=async_session,
model=YourModel,
create_schema=CreateYourModelSchema,
update_schema=UpdateYourModelSchema,
filter_config=filter_config, Apply the filter configuration
path="/yourmodel",
tags=["YourModel"]
)
)


Using Filters in Requests

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


Custom Filter Validation

The `FilterConfig` class includes a validator to check filter types. If an invalid filter type is provided, a `ValueError` is raised. You can customize the validation logic by extending the `FilterConfig` class:

python
from fastcrud import FilterConfig
from pydantic import ValidationError

class CustomFilterConfig(FilterConfig):
field_validator("filters")
def check_filter_types(cls, filters: dict[str, Any]) -> dict[str, Any]:
for key, value in filters.items():
if not isinstance(value, (type(None), str, int, float, bool)):
raise ValueError(f"Invalid default value for '{key}': {value}")
return filters

try:
Example of invalid filter configuration
invalid_filter_config = CustomFilterConfig(invalid_field=[])
except ValidationError as e:
print(e)


Handling Invalid Filter Columns

FastCRUD ensures that filters are applied only to valid columns in your model. If an invalid filter column is specified, a `ValueError` is raised:

python
try:
Example of invalid filter column
invalid_filter_config = FilterConfig(non_existent_column=None)
except ValueError as e:
print(e) Output: Invalid filter column 'non_existent_column': not found in model


___
Handling One-to-One and One-to-Many Joins in FastCRUD

FastCRUD provides flexibility in handling one-to-one and one-to-many relationships through `get_joined` and `get_multi_joined` methods, along with the ability to specify how joined data should be structured using both the `relationship_type` (default `one-to-one`) and the `nest_joins` (default `False`) parameters.

One-to-One Relationships
- **`get_joined`**: Fetch a single record and its directly associated record (e.g., a user and their profile).
- **`get_multi_joined`** (with `nest_joins=False`): Retrieve multiple records, each linked to a single related record from another table (e.g., users and their profiles).


**Example**

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)


Fetch a user and their tier:

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
)


The result will be:

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


**One-to-One Relationship with Nested Joins**

To get the joined data in a nested dictionary:

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
)


The result will be:

json
{
"id": 1,
"name": "Example",
"tier": {
"id": 1,
"name": "Free"
}
}



One-to-Many Relationships
- **`get_joined`** (with `nest_joins=True`): Retrieve a single record with all its related records nested within it (e.g., a user and all their blog posts).
- **`get_multi_joined`** (with `nest_joins=True`): Fetch multiple primary records, each with their related records nested (e.g., multiple users and all their blog posts).

!!! WARNING
When using `nest_joins=True`, the performance will always be a bit worse than when using `nest_joins=False`. For cases where more performance is necessary, consider using `nest_joins=False` and remodeling your database.


**Example**

To demonstrate a one-to-many relationship, let's assume `User` and `Post` tables:

python
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary key=True)
name = Column(String)

class Post(Base):
__tablename__ = "post"
id = Column(Integer, primary key=True)
user_id = Column(Integer, ForeignKey("user.id"))
content = Column(String)


Fetch a user and all their posts:

python
user_posts = await user_crud.get_joined(
db=db,
join_model=Post,
join_on=User.id == Post.user_id,
join_type="left",
join_prefix="post_",
nest_joins=True,
id=1
)


The result will be:

json
{
"id": 1,
"name": "Example User",
"posts": [
{
"id": 101,
"user_id": 1,
"content": "First post content"
},
{
"id": 102,
"user_id": 1,
"content": "Second post content"
}
]
}



What's Changed
- feat: ✨ add upsert method in FastCRUD class by [dubusster](https://github.com/dubusster)
- Filters in Automatic Endpoints
- One-to-many support in joins
- tests fixed by igorbenav
- Using the same session for all tests
- warning added to docs


**Full Changelog**: https://github.com/igorbenav/fastcrud/compare/v0.12.1...v0.13.0

0.12.1

Added
- Deprecation Warning for dependency handling.

___
Detailed Changes

If you pass a sequence of `params.Depends` type variables to any `*_deps` parameter in `EndpointCreator` and `crud_router`, you'll get a warning. Support will be completely removed in 0.15.0.

**Full Changelog**: https://github.com/igorbenav/fastcrud/compare/v0.12.0...v0.12.1

Page 1 of 4

Β© 2024 Safety CLI Cybersecurity Inc. All Rights Reserved.