Scalable data access patterns for rapid API development, using SQLAlchemy & Pydantic.
Project description
OnePattern
Scalable data access patterns for rapid API development, using SQLAlchemy & Pydantic.
Features
- Focus on business logic: No need to write boilerplate code.
- Scalable: You can use the provided abstractions and easily extend them.
- Portable: Works with any database supported by SQLAlchemy.
- Intuitive: Great editor support. Completion everywhere. Less time debugging.
- Easy: Designed to be easy to use and learn. Less time reading docs.
- Asynchronous: Built-in support for async/await.
- Use anywhere: Use it with FastAPI, Aiogram, or any other framework.
Requirements
OnePattern stands on the shoulders of giants:
Installation
pip install onepattern
Concepts
1. Models
from datetime import datetime
from sqlalchemy import Identity
from sqlalchemy.orm import Mapped, mapped_column
from onepattern import DeclarativeBase, AlchemyEntity
from onepattern.alchemy import SoftDeletable, HasID, HasTimestamp
# Classic way
class User(DeclarativeBase):
__tablename__ = "users"
id: Mapped[int] = mapped_column(Identity(), primary_key=True)
email: Mapped[str] = mapped_column(unique=True, index=True)
password: Mapped[str]
created_at: Mapped[datetime] = mapped_column(default=datetime.now)
updated_at: Mapped[datetime] = mapped_column(
default=datetime.now, onupdate=datetime.now
)
# Using AlchemyEntity
class UserAlchemyEntity(AlchemyEntity):
__tablename__ = "users"
email: Mapped[str] = mapped_column(unique=True, index=True)
password: Mapped[str]
# These columns will be added automatically
# id: Mapped[int] = mapped_column(Identity(), primary_key=True)
# created_at: Mapped[datetime] = mapped_column(default=datetime.now)
# updated_at: Mapped[datetime] = mapped_column(
# default=datetime.now, onupdate=datetime.now
# )
# Using mixins
class UserMixins(HasID, HasTimestamp, SoftDeletable):
__tablename__ = "users"
email: Mapped[str] = mapped_column(unique=True, index=True)
password: Mapped[str]
# These columns will be added automatically
# id: Mapped[int]
# created_at: Mapped[datetime] = mapped_column(default=datetime.now)
# updated_at: Mapped[datetime] = mapped_column(
# default=datetime.now, onupdate=datetime.now
# )
# deleted_at: Mapped[datetime | None] = None
2. Repositories
from onepattern import AlchemyRepository
from .models import User
class UserRepository(AlchemyRepository[User]):
model_type = User
3. Unit of Work
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from onepattern import AlchemyUOW
from .repositories import UserRepository
class UOW(AlchemyUOW):
users: UserRepository
async def on_open(self) -> None:
self.users = UserRepository(self.session)
async_engine = create_async_engine("sqlite+aiosqlite:///memory")
async_session = async_sessionmaker(async_engine)
uow = UOW(async_session)
4. Services
from onepattern import AlchemyService
from .models import User
from .uow import UOW
class UserService(AlchemyService):
uow: UOW
async def create(self, email: str, password: str) -> User:
user = User(email=email, password=password)
self.uow.users.add(user)
await self.uow.commit()
return user
async def get(self, user_id: int) -> User | None:
return await self.uow.users.get(user_id)
async def get_by_email(self, email: str) -> User | None:
return await self.uow.users.get_by_where(where=[User.email == email])
async def create_many(self, users: list[User]) -> list[User]:
await self.uow.users.insert(*users)
await self.uow.commit()
return users
async def get_by_domain(self, domain: str) -> list[User]:
return await self.uow.users.get_many(where=[User.email.like(f"%@{domain}")])
# And more...
5. Use Cases
from faker import Faker
from .models import User
from .service import UserService
from .uow import uow
fake = Faker()
def get_users(domains: list[str], number: int = 10) -> list[User]:
users = [User(email=fake.email(domain=domain), password=fake.password()) for _ in range(number) for domain in
domains]
return users
async def main():
async with uow:
service = UserService(uow)
user = await service.create("user@example.com", "qwerty12345")
print(user)
user = await service.get(user.id)
print(user)
user = await service.get_by_email("user@example.com")
print(user)
users = get_users(["gmail.com", "yahoo.com"])
await service.create_many(*users)
users = await service.get_by_domain("gmail.com")
print(users)
Made with love ❤️
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
onepattern-0.1.9.tar.gz
(11.0 kB
view details)
Built Distribution
File details
Details for the file onepattern-0.1.9.tar.gz
.
File metadata
- Download URL: onepattern-0.1.9.tar.gz
- Upload date:
- Size: 11.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.2 CPython/3.12.3 Windows/11
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | b655b3cb2cc78200f77a4682dd9ab80351ade3f7ef29ca938e266afd991b4f66 |
|
MD5 | d9d71092fa64292826eb7ae76b050f72 |
|
BLAKE2b-256 | f1826e208367c26d81046987e705927a221ce82aa17cecb635f2a2a2bbd54dd9 |
File details
Details for the file onepattern-0.1.9-py3-none-any.whl
.
File metadata
- Download URL: onepattern-0.1.9-py3-none-any.whl
- Upload date:
- Size: 16.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.8.2 CPython/3.12.3 Windows/11
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5298f253de385a64cdfb48bec9946002945ca1b509aa377fde75441cb026c90b |
|
MD5 | a763e1a363aba041a582fe27ed5c999d |
|
BLAKE2b-256 | f82777473d857b5920444070008b4ff7946696be522abb1527793c7cd99a725e |