Helper class for upserting records to database
Project description
Sadel
Sadel is a helper class for upserting records with SQLModel. Sadel combines SQLAlchemy ('sa') and SQLmodel ('del'), and in Danish, 'sadel' means 'saddle' symbolizing taking over the burden of managing upserts.
Installation
pip install sadel
Features
- Upsert and batch_upsert functions.
- For auditing, automatically adds and manages
created_on
andmodified_on
columns to your table (timezones are supported). - Validates your data before upserting using Pydantic validate_model method (not supported in SQLModel)
- Asyncio
- Compatible with Alembic
- Specify the (PK) columns to use for upserting using
_upsert_index_elements
attribute - Ignore specific columns from updating using
_upsert_exclude_fields
attribute
Example upsert
from sadel import Sadel
from sqlalchemy.ext.asyncio import create_async_engine
from sqlmodel import Field, create_engine, select, or_
from sqlmodel.ext.asyncio.session import AsyncSession
class Hero(Sadel, table=True):
__tablename__ = "hero"
_upsert_index_elements = {"id"}
id: int | None = Field(default=None, primary_key=True)
name: str
secret_name: str
age: int | None = None
sqlite_url = f"sqlite+aiosqlite::///database.db"
engine = create_engine(sqlite_url, echo=True, future=True)
async_engine = create_async_engine(sqlite_url_async, echo=True, future=True)
hero = Hero(name="Deadpond", secret_name="Dive Wilson")
async with AsyncSession(async_engine) as session:
# Upsert the record
await Hero.upsert(hero, session)
# Fetch the upserted record
result = (
(await session.exec(select(Hero).where(Hero.name == "Deadpond")))
.all()
)
print(result)
Output:
[Hero(id=1, name='Deadpond', secret_name='Dive Wilson', age=None, created_on=datetime.datetime(2024, 8, 1, 19, 39, 7), modified_on=None)]
Example batch upsert
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)
async with AsyncSession(async_engine) as session:
await Hero.batch_upsert([hero_1, hero_2, hero_3], session)
result = (
(
await session.exec(
select(Hero).where(or_(Hero.name == "Deadpond", Hero.name == "Spider-Boy", Hero.name == "Rusty-Man"))
)
)
.all()
)
print(result)
Output:
[Hero(id=1, name='Deadpond', secret_name='Dive Wilson',age=None, created_on=datetime.datetime(2024, 8, 1, 19, 39, 7), modified_on=None),
Hero(id=2, name='Spider-Boy", secret_name='Pedro Parqueador',age=None, created_on=datetime.datetime(2024, 8, 1, 19, 39, 7), modified_on=None),
Hero(id=3, name='Rusty-Man', secret_name='Tommy Sharp', age=48, created_on=datetime.datetime(2024, 8, 1, 19, 39, 7), modified_on=None)]
Example update record
async with AsyncSession(async_engine) as session:
# Upsert the record
hero = Hero(name="Deadpond", secret_name="Dive Wilson", age=25)
await Hero.upsert(hero, session)
# Update the record
hero.age = 30
# Upsert the updated record
await Hero.upsert(hero, session)
# Fetch the updated record
result = (
(await session.exec(select(Hero).where(Hero.name == "Deadpond")))
.scalars()
.all()
)
print(result)
Output:
[Hero(id=1, name='Deadpond', secret_name='Dive Wilson', age=30, created_on=datetime.datetime(2024, 8, 1, 19, 39, 7), modified_on=datetime.datetime(2024, 8, 1, 19, 39, 8))]
Contributing
- Fork the repository
- Create a new branch
- Make your changes
- Raise a PR
Development
# install dependencies
rye sync
# run tests, linting, formatting, and type checking,
rye run all
License
This project is licensed under the terms of the MIT License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
sadel-0.1.0.tar.gz
(5.1 kB
view details)
Built Distribution
sadel-0.1.0-py3-none-any.whl
(4.8 kB
view details)
File details
Details for the file sadel-0.1.0.tar.gz
.
File metadata
- Download URL: sadel-0.1.0.tar.gz
- Upload date:
- Size: 5.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.0 CPython/3.12.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7eae99fcd9637fa58e0692041134256b53682571fb0d7efa6eb9c086c139ef5e |
|
MD5 | 06770fd999c271b2dc28d8f297e56538 |
|
BLAKE2b-256 | c3198b812bd45f3ba8088ce1f872e0fcadf6af7e26a1152d756e155e9a02f233 |
File details
Details for the file sadel-0.1.0-py3-none-any.whl
.
File metadata
- Download URL: sadel-0.1.0-py3-none-any.whl
- Upload date:
- Size: 4.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.0 CPython/3.12.4
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3e4efe0ccaf2dd973623f400d777b59d5ac6fc8aa9f9a2b52d19a224f0ff8d0d |
|
MD5 | 3539061f678cb901795795e7b862dc65 |
|
BLAKE2b-256 | e63aff50bfaed4181ee8a16a0e5a604f2f8d327c0a020b982d56dfebda1809ba |