{"id":43918172,"url":"https://github.com/dperezcabrera/pico-sqlalchemy","last_synced_at":"2026-02-20T22:27:49.816Z","repository":{"id":324593794,"uuid":"1097752854","full_name":"dperezcabrera/pico-sqlalchemy","owner":"dperezcabrera","description":"Lightweight SQLAlchemy integration for Pico-IoC, with full transactional semantics, repository support, and declarative model bootstrapping.","archived":false,"fork":false,"pushed_at":"2026-02-16T08:37:06.000Z","size":167,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-16T16:17:25.378Z","etag":null,"topics":["async","asyncio","database","dependency-injection","ioc","orm","pico-framework","repository-pattern","sqlalchemy","transactions"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dperezcabrera.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-11-16T19:03:28.000Z","updated_at":"2026-02-16T08:37:03.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dperezcabrera/pico-sqlalchemy","commit_stats":null,"previous_names":["dperezcabrera/pico-sqlalchemy"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/dperezcabrera/pico-sqlalchemy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dperezcabrera%2Fpico-sqlalchemy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dperezcabrera%2Fpico-sqlalchemy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dperezcabrera%2Fpico-sqlalchemy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dperezcabrera%2Fpico-sqlalchemy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dperezcabrera","download_url":"https://codeload.github.com/dperezcabrera/pico-sqlalchemy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dperezcabrera%2Fpico-sqlalchemy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29667088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T19:49:36.704Z","status":"ssl_error","status_checked_at":"2026-02-20T19:44:05.372Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","asyncio","database","dependency-injection","ioc","orm","pico-framework","repository-pattern","sqlalchemy","transactions"],"created_at":"2026-02-06T22:03:01.891Z","updated_at":"2026-02-20T22:27:49.809Z","avatar_url":"https://github.com/dperezcabrera.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 📦 pico-sqlalchemy\n\n[![PyPI](https://img.shields.io/pypi/v/pico-sqlalchemy.svg)](https://pypi.org/project/pico-sqlalchemy/)\n[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dperezcabrera/pico-sqlalchemy)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n![CI (tox matrix)](https://github.com/dperezcabrera/pico-sqlalchemy/actions/workflows/ci.yml/badge.svg)\n[![codecov](https://codecov.io/gh/dperezcabrera/pico-sqlalchemy/branch/main/graph/badge.svg)](https://codecov.io/gh/dperezcabrera/pico-sqlalchemy)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-sqlalchemy\\\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-sqlalchemy)\n[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-sqlalchemy\\\u0026metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-sqlalchemy)\n[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-sqlalchemy\\\u0026metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-sqlalchemy)\n[![Docs](https://img.shields.io/badge/Docs-pico--sqlalchemy-blue?style=flat\u0026logo=readthedocs\u0026logoColor=white)](https://dperezcabrera.github.io/pico-sqlalchemy/)\n\n# Pico-SQLAlchemy\n\n**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.\n\nIt brings constructor-based dependency injection, **implicit transaction management**, and powerful **declarative queries** using pure Python and SQLAlchemy’s Async ORM.\n\n\u003e 🐍 **Requires Python 3.11+**\n\u003e 🚀 **Async-Native:** Built entirely on `AsyncSession` and `create_async_engine`.\n\u003e ✨ **Zero-Boilerplate:** Repositories are transactional by default.\n\u003e 🔍 **Declarative Queries:** Define SQL or expressions in decorators; the library executes them for you.\n\n---\n\n## 🎯 Why pico-sqlalchemy?\n\nMost Python apps suffer from manual session handling (`async with session...`), scattered transaction logic, and verbose repository patterns.\n\n**Pico-SQLAlchemy** solves this by offering:\n\n| Feature | SQLAlchemy Default | pico-sqlalchemy |\n| :--- | :--- | :--- |\n| **Transactions** | Manual `commit()` / `rollback()` | **Implicit** (Auto-managed) |\n| **Repositories** | DIY Classes | **`@repository`** (Transactional by default) |\n| **Queries** | Manual implementation | **`@query`** (Declarative execution) |\n| **Injection** | None / Global variables | **Constructor Injection** (IoC) |\n| **Pagination** | Manual calculation | **Automatic** (`PageRequest` / `Page`) |\n\n---\n\n## 🧱 Core Features\n\n* **Implicit Transactions:** Methods inside `@repository` are automatically **Read-Write** transactional.\n* **Declarative Queries:** Use `@query` to run SQL or Expressions automatically (defaults to **Read-Only**).\n* **AOP-Based Propagation:** `REQUIRED`, `REQUIRES_NEW`, `MANDATORY`, `NEVER`, etc.\n* **Session Lifecycle:** Centralized `SessionManager` handles engine creation and cleanup.\n* **Pagination:** Built-in support for paged results via `@query(paged=True)`.\n\n---\n\n## 📦 Installation\n\n```bash\npip install pico-sqlalchemy\n```\n\nYou will also need an async database driver:\n\n```bash\npip install aiosqlite   # for SQLite\npip install asyncpg     # for PostgreSQL\n```\n\n-----\n\n## 🚀 Quick Example\n\n### 1\\. Define Model\n\n```python\nfrom sqlalchemy import Integer, String\nfrom pico_sqlalchemy import AppBase, Mapped, mapped_column\n\nclass User(AppBase):\n    __tablename__ = \"users\"\n    id: Mapped[int] = mapped_column(Integer, primary_key=True)\n    username: Mapped[str] = mapped_column(String(50))\n```\n\n### 2\\. Define Repository (The \"Magic\" Part)\n\nNotice we don't need `@transactional` here.\n\n  * `save`: Automatically runs in a **Read-Write** transaction.\n  * `find_by_name`: Automatically runs in a **Read-Only** transaction and executes the query logic.\n\n\u003c!-- end list --\u003e\n\n```python\nfrom pico_sqlalchemy import repository, query, SessionManager, get_session\n\n@repository(entity=User)\nclass UserRepository:\n    def __init__(self, manager: SessionManager):\n        self.manager = manager\n\n    # IMPLICIT: Read-Write Transaction\n    async def save(self, user: User) -\u003e User:\n        session = get_session(self.manager)\n        session.add(user)\n        return user\n\n    # DECLARATIVE: Read-Only Transaction + Auto-Execution\n    @query(expr=\"username = :username\", unique=True)\n    async def find_by_name(self, username: str) -\u003e User | None:\n        ... # Body is ignored; the library executes the query\n```\n\n### 3\\. Define Service\n\nUse `@transactional` here to define business logic boundaries.\n\n```python\nfrom pico_ioc import component\nfrom pico_sqlalchemy import transactional\n\n@component\nclass UserService:\n    def __init__(self, repo: UserRepository):\n        self.repo = repo\n\n    @transactional\n    async def create(self, name: str) -\u003e User:\n        # 1. Check existence (Read-Only tx from repo)\n        existing = await self.repo.find_by_name(name)\n        if existing:\n            raise ValueError(\"User exists\")\n            \n        # 2. Save new user (Joins current transaction)\n        return await self.repo.save(User(username=name))\n```\n\n### 4\\. Run it\n\n```python\nimport asyncio\nfrom pico_ioc import init, configuration, DictSource\n\nconfig = configuration(DictSource({\n    \"database\": {\n        \"url\": \"sqlite+aiosqlite:///:memory:\",\n        \"echo\": False\n    }\n}))\n\nasync def main():\n    container = init(modules=[\"pico_sqlalchemy\", \"__main__\"], config=config)\n    service = await container.aget(UserService)\n    \n    user = await service.create(\"alice\")\n    print(f\"Created: {user.id}\")\n    \n    await container.cleanup_all_async()\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n-----\n\n## ⚡ Transaction Hierarchy \u0026 Rules\n\nPico-SQLAlchemy applies a \"Best Effort\" strategy to determine transaction configuration. The priority order (highest wins) is:\n\n| Priority | Decorator | Default Mode | Use Case |\n| :--- | :--- | :--- | :--- |\n| **1 (High)** | **`@transactional(...)`** | Explicit Config | Overriding defaults, Service layer logic. |\n| **2** | **`@query(...)`** | **Read-Only** | Efficient data fetching. |\n| **3 (Base)** | **`@repository`** | **Read-Write** | Default for CRUD (saves, updates, deletes). |\n\n### Example Scenarios\n\n1.  **Plain Method in Repository:**\n\n    ```python\n    async def update_user(self): ...\n    ```\n\n    👉 **Result:** Active Read-Write Transaction (Implicit from `@repository`).\n\n2.  **Query Method:**\n\n    ```python\n    @query(\"SELECT ...\")\n    async def get_data(self): ...\n    ```\n\n    👉 **Result:** Active Read-Only Transaction (Implicit from `@query`).\n\n3.  **Manual Override:**\n\n    ```python\n    @transactional(read_only=True)\n    async def complex_report(self): ...\n    ```\n\n    👉 **Result:** Active Read-Only Transaction (Explicit override).\n\n-----\n\n## 🔍 Declarative Queries in Depth\n\nThe `@query` decorator eliminates boilerplate for common fetches.\n\n### Expression Mode (`expr`)\n\nRequires `@repository(entity=Model)`. Injects the expression into a `SELECT * FROM table WHERE ...`.\n\n```python\n@query(expr=\"age \u003e :min_age\", unique=False)\nasync def find_adults(self, min_age: int) -\u003e list[User]: ...\n```\n\n### SQL Mode (`sql`)\n\nExecutes raw SQL. Useful for complex joins or specific DTOs.\n\n```python\n@query(sql=\"SELECT count(*) as cnt FROM users\")\nasync def count_users(self) -\u003e int: ...\n```\n\n### Automatic Pagination\n\nJust add `paged=True` and a `page: PageRequest` parameter.\n\n```python\nfrom pico_sqlalchemy import Page, PageRequest\n\n@query(expr=\"active = true\", paged=True)\nasync def find_active(self, page: PageRequest) -\u003e Page[User]: ...\n```\n\n-----\n\n## 🧪 Testing\n\nTesting is simple because you can override the configuration or the components easily using Pico-IoC.\n\n```python\n@pytest.mark.asyncio\nasync def test_service():\n    # Setup container with in-memory DB\n    container = ... \n    \n    service = await container.aget(UserService)\n    user = await service.create(\"test\")\n    \n    assert user.id is not None\n```\n\n-----\n\n## 💡 Architecture Overview\n\n```\n                 ┌─────────────────────────────┐\n                 │          Your App           │\n                 └──────────────┬──────────────┘\n                                │\n                        Constructor Injection\n                                │\n                 ┌──────────────▼───────────────┐\n                 │          Pico-IoC            │\n                 └──────────────┬───────────────┘\n                                │\n                 ┌──────────────▼───────────────┐\n                 │       pico-sqlalchemy        │\n                 │ 1. Implicit Repo Transactions│\n                 │ 2. Declarative @query        │\n                 │ 3. Explicit @transactional   │\n                 └──────────────┬───────────────┘\n                                │\n                           SQLAlchemy\n                           (Async ORM)\n```\n\n-----\n\n## AI Coding Skills\n\nInstall [Claude Code](https://code.claude.com) or [OpenAI Codex](https://openai.com/index/introducing-codex/) skills for AI-assisted development with pico-sqlalchemy:\n\n```bash\ncurl -sL https://raw.githubusercontent.com/dperezcabrera/pico-skills/main/install.sh | bash -s -- sqlalchemy\n```\n\n| Command | Description |\n|---------|-------------|\n| `/add-repository` | Add SQLAlchemy entities and repositories with transactions |\n| `/add-component` | Add components, factories, interceptors, settings |\n| `/add-tests` | Generate tests for pico-framework components |\n\nAll skills: `curl -sL https://raw.githubusercontent.com/dperezcabrera/pico-skills/main/install.sh | bash`\n\nSee [pico-skills](https://github.com/dperezcabrera/pico-skills) for details.\n\n---\n\n## 📝 License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdperezcabrera%2Fpico-sqlalchemy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdperezcabrera%2Fpico-sqlalchemy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdperezcabrera%2Fpico-sqlalchemy/lists"}