https://github.com/dperezcabrera/pico-sqlalchemy
Lightweight SQLAlchemy integration for Pico-IoC, with full transactional semantics, repository support, and declarative model bootstrapping.
https://github.com/dperezcabrera/pico-sqlalchemy
async asyncio database dependency-injection ioc orm pico-framework repository-pattern sqlalchemy transactions
Last synced: 5 months ago
JSON representation
Lightweight SQLAlchemy integration for Pico-IoC, with full transactional semantics, repository support, and declarative model bootstrapping.
- Host: GitHub
- URL: https://github.com/dperezcabrera/pico-sqlalchemy
- Owner: dperezcabrera
- License: mit
- Created: 2025-11-16T19:03:28.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2026-02-16T08:37:06.000Z (5 months ago)
- Last Synced: 2026-02-16T16:17:25.378Z (5 months ago)
- Topics: async, asyncio, database, dependency-injection, ioc, orm, pico-framework, repository-pattern, sqlalchemy, transactions
- Language: Python
- Size: 163 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# π¦ pico-sqlalchemy
[](https://pypi.org/project/pico-sqlalchemy/)
[](https://deepwiki.com/dperezcabrera/pico-sqlalchemy)
[](https://opensource.org/licenses/MIT)

[](https://codecov.io/gh/dperezcabrera/pico-sqlalchemy)
[](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-sqlalchemy)
[](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-sqlalchemy)
[](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-sqlalchemy)
[](https://dperezcabrera.github.io/pico-sqlalchemy/)
# Pico-SQLAlchemy
**Pico-SQLAlchemy** integrates **[Pico-IoC](https://github.com/dperezcabrera/pico-ioc)** with **SQLAlchemy**, providing a true inversion of control persistence layer with **Spring Data-style** declarative features.
It brings constructor-based dependency injection, **implicit transaction management**, and powerful **declarative queries** using pure Python and SQLAlchemyβs Async ORM.
> π **Requires Python 3.11+**
> π **Async-Native:** Built entirely on `AsyncSession` and `create_async_engine`.
> β¨ **Zero-Boilerplate:** Repositories are transactional by default.
> π **Declarative Queries:** Define SQL or expressions in decorators; the library executes them for you.
---
## π― Why pico-sqlalchemy?
Most Python apps suffer from manual session handling (`async with session...`), scattered transaction logic, and verbose repository patterns.
**Pico-SQLAlchemy** solves this by offering:
| Feature | SQLAlchemy Default | pico-sqlalchemy |
| :--- | :--- | :--- |
| **Transactions** | Manual `commit()` / `rollback()` | **Implicit** (Auto-managed) |
| **Repositories** | DIY Classes | **`@repository`** (Transactional by default) |
| **Queries** | Manual implementation | **`@query`** (Declarative execution) |
| **Injection** | None / Global variables | **Constructor Injection** (IoC) |
| **Pagination** | Manual calculation | **Automatic** (`PageRequest` / `Page`) |
---
## π§± Core Features
* **Implicit Transactions:** Methods inside `@repository` are automatically **Read-Write** transactional.
* **Declarative Queries:** Use `@query` to run SQL or Expressions automatically (defaults to **Read-Only**).
* **AOP-Based Propagation:** `REQUIRED`, `REQUIRES_NEW`, `MANDATORY`, `NEVER`, etc.
* **Session Lifecycle:** Centralized `SessionManager` handles engine creation and cleanup.
* **Pagination:** Built-in support for paged results via `@query(paged=True)`.
---
## π¦ Installation
```bash
pip install pico-sqlalchemy
```
You will also need an async database driver:
```bash
pip install aiosqlite # for SQLite
pip install asyncpg # for PostgreSQL
```
-----
## π Quick Example
### 1\. Define Model
```python
from sqlalchemy import Integer, String
from pico_sqlalchemy import AppBase, Mapped, mapped_column
class User(AppBase):
__tablename__ = "users"
id: Mapped[int] = mapped_column(Integer, primary_key=True)
username: Mapped[str] = mapped_column(String(50))
```
### 2\. Define Repository (The "Magic" Part)
Notice we don't need `@transactional` here.
* `save`: Automatically runs in a **Read-Write** transaction.
* `find_by_name`: Automatically runs in a **Read-Only** transaction and executes the query logic.
```python
from pico_sqlalchemy import repository, query, SessionManager, get_session
@repository(entity=User)
class UserRepository:
def __init__(self, manager: SessionManager):
self.manager = manager
# IMPLICIT: Read-Write Transaction
async def save(self, user: User) -> User:
session = get_session(self.manager)
session.add(user)
return user
# DECLARATIVE: Read-Only Transaction + Auto-Execution
@query(expr="username = :username", unique=True)
async def find_by_name(self, username: str) -> User | None:
... # Body is ignored; the library executes the query
```
### 3\. Define Service
Use `@transactional` here to define business logic boundaries.
```python
from pico_ioc import component
from pico_sqlalchemy import transactional
@component
class UserService:
def __init__(self, repo: UserRepository):
self.repo = repo
@transactional
async def create(self, name: str) -> User:
# 1. Check existence (Read-Only tx from repo)
existing = await self.repo.find_by_name(name)
if existing:
raise ValueError("User exists")
# 2. Save new user (Joins current transaction)
return await self.repo.save(User(username=name))
```
### 4\. Run it
```python
import asyncio
from pico_ioc import init, configuration, DictSource
config = configuration(DictSource({
"database": {
"url": "sqlite+aiosqlite:///:memory:",
"echo": False
}
}))
async def main():
container = init(modules=["pico_sqlalchemy", "__main__"], config=config)
service = await container.aget(UserService)
user = await service.create("alice")
print(f"Created: {user.id}")
await container.cleanup_all_async()
if __name__ == "__main__":
asyncio.run(main())
```
-----
## β‘ Transaction Hierarchy & Rules
Pico-SQLAlchemy applies a "Best Effort" strategy to determine transaction configuration. The priority order (highest wins) is:
| Priority | Decorator | Default Mode | Use Case |
| :--- | :--- | :--- | :--- |
| **1 (High)** | **`@transactional(...)`** | Explicit Config | Overriding defaults, Service layer logic. |
| **2** | **`@query(...)`** | **Read-Only** | Efficient data fetching. |
| **3 (Base)** | **`@repository`** | **Read-Write** | Default for CRUD (saves, updates, deletes). |
### Example Scenarios
1. **Plain Method in Repository:**
```python
async def update_user(self): ...
```
π **Result:** Active Read-Write Transaction (Implicit from `@repository`).
2. **Query Method:**
```python
@query("SELECT ...")
async def get_data(self): ...
```
π **Result:** Active Read-Only Transaction (Implicit from `@query`).
3. **Manual Override:**
```python
@transactional(read_only=True)
async def complex_report(self): ...
```
π **Result:** Active Read-Only Transaction (Explicit override).
-----
## π Declarative Queries in Depth
The `@query` decorator eliminates boilerplate for common fetches.
### Expression Mode (`expr`)
Requires `@repository(entity=Model)`. Injects the expression into a `SELECT * FROM table WHERE ...`.
```python
@query(expr="age > :min_age", unique=False)
async def find_adults(self, min_age: int) -> list[User]: ...
```
### SQL Mode (`sql`)
Executes raw SQL. Useful for complex joins or specific DTOs.
```python
@query(sql="SELECT count(*) as cnt FROM users")
async def count_users(self) -> int: ...
```
### Automatic Pagination
Just add `paged=True` and a `page: PageRequest` parameter.
```python
from pico_sqlalchemy import Page, PageRequest
@query(expr="active = true", paged=True)
async def find_active(self, page: PageRequest) -> Page[User]: ...
```
-----
## π§ͺ Testing
Testing is simple because you can override the configuration or the components easily using Pico-IoC.
```python
@pytest.mark.asyncio
async def test_service():
# Setup container with in-memory DB
container = ...
service = await container.aget(UserService)
user = await service.create("test")
assert user.id is not None
```
-----
## π‘ Architecture Overview
```
βββββββββββββββββββββββββββββββ
β Your App β
ββββββββββββββββ¬βββββββββββββββ
β
Constructor Injection
β
ββββββββββββββββΌββββββββββββββββ
β Pico-IoC β
ββββββββββββββββ¬ββββββββββββββββ
β
ββββββββββββββββΌββββββββββββββββ
β pico-sqlalchemy β
β 1. Implicit Repo Transactionsβ
β 2. Declarative @query β
β 3. Explicit @transactional β
ββββββββββββββββ¬ββββββββββββββββ
β
SQLAlchemy
(Async ORM)
```
-----
## AI Coding Skills
Install [Claude Code](https://code.claude.com) or [OpenAI Codex](https://openai.com/index/introducing-codex/) skills for AI-assisted development with pico-sqlalchemy:
```bash
curl -sL https://raw.githubusercontent.com/dperezcabrera/pico-skills/main/install.sh | bash -s -- sqlalchemy
```
| Command | Description |
|---------|-------------|
| `/add-repository` | Add SQLAlchemy entities and repositories with transactions |
| `/add-component` | Add components, factories, interceptors, settings |
| `/add-tests` | Generate tests for pico-framework components |
All skills: `curl -sL https://raw.githubusercontent.com/dperezcabrera/pico-skills/main/install.sh | bash`
See [pico-skills](https://github.com/dperezcabrera/pico-skills) for details.
---
## π License
MIT