Skip to main content

SQLAlchemy async backend for varco — runtime ORM generation, repository, schema guard, and Alembic helpers

Project description

varco-sa

PyPI version Python License: Apache 2.0 GitHub

SQLAlchemy async backend for varco.

Generates SQLAlchemy ORM classes at runtime from your DomainModel subclasses — no hand-written ORM models needed. Requires varco-core.


Install

pip install varco-sa

# With PostgreSQL async driver:
pip install "varco-sa[postgresql]"

# With SQLite (tests / local dev):
pip install "varco-sa[sqlite]"

Features

  • Zero-boilerplate ORMSAModelFactory generates DeclarativeBase subclasses at runtime; no duplication between domain and ORM layers
  • Full async repositoryAsyncSQLAlchemyRepository implements AsyncRepository (CRUD, exists(), stream_by_query() with server-side cursor)
  • Unit of WorkSQLAlchemyUnitOfWork manages AsyncSession lifecycle and atomic commits
  • One-liner bootstrapSAFastrestApp + SAConfig wire engine, session factory, ORM generation, and table creation
  • Alembic integrationget_target_metadata() and print_create_ddl() helpers for migration scripts
  • Schema GuardSchemaGuard detects drift between ORM metadata and the live database schema
  • Query integration — accepts varco-core QueryParams / QueryBuilder AST natively; translates to SQLAlchemy where() clauses

What's in the package

Module Purpose
factory.py SAModelFactory — generates DeclarativeBase subclasses at runtime; SAModelRegistry — escape hatch
repository.py AsyncSQLAlchemyRepositoryAsyncSession-backed CRUD + exists() + stream_by_query()
uow.py SQLAlchemyUnitOfWork — session lifecycle + atomic commits
provider.py SQLAlchemyRepositoryProvider — wires factory + repos + UoW
bootstrap.py SAConfig, SAFastrestApp — one-liner app setup
alembic_helpers.py get_target_metadata, print_create_ddl — Alembic integration
schema_guard.py SchemaGuard — drift detection between ORM metadata and live DB

Quick start

Bootstrap (one-liner)

from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import DeclarativeBase
from varco_sa import SAConfig, SAFastrestApp

class Base(DeclarativeBase): pass

engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/mydb")

app = SAFastrestApp(SAConfig(
    engine=engine,
    base=Base,
    entity_classes=(User, Post),
))

await app.create_all()              # CREATE TABLE IF NOT EXISTS ...
uow_provider = app.uow_provider     # ready to inject as IUoWProvider

Manual setup

from sqlalchemy.ext.asyncio import async_sessionmaker
from varco_sa import SQLAlchemyRepositoryProvider

sessions = async_sessionmaker(engine, expire_on_commit=False)
provider = SQLAlchemyRepositoryProvider(engine=engine, session_factory=sessions)
provider.register(User, Post)
await provider.create_all()

async with provider.make_uow() as uow:
    user = await uow.users.save(User(name="Edo", email="edo@example.com"))
    print(user.pk)

Query integration

from varco_core import QueryBuilder, QueryParams

async with provider.make_uow() as uow:
    # exists() — uses SA identity-map cache, no full ORM load when cached
    if await uow.posts.exists(post_id):
        ...

    # stream_by_query() — server-side cursor, constant memory regardless of result size
    params = QueryParams(node=QueryBuilder().eq("active", True).build())
    async for post in uow.posts.stream_by_query(params):
        await process(post)

Alembic integration

# alembic/env.py
from varco_sa import get_target_metadata
from myapp.models import User, Post

target_metadata = get_target_metadata(User, Post)

Preview the DDL before running a migration:

from varco_sa import print_create_ddl

print(print_create_ddl(User, Post, dialect="postgresql"))

Schema Guard — detect drift

from varco_sa import SchemaGuard

guard = SchemaGuard(engine, User, Post)
differences = await guard.check()
if differences:
    print("Schema drift detected:", differences)

Access the generated SA model (escape hatch)

from varco_sa import SAModelRegistry
from sqlalchemy.orm import relationship

UserORM = SAModelRegistry.get(User)
UserORM.posts = relationship("PostORM", back_populates="author")

Connection settings

PostgresConnectionSettings is a structured, env-var loadable config object that produces driver-ready output for asyncpg and SQLAlchemy.

Plain connection

from varco_sa.connection import PostgresConnectionSettings
from sqlalchemy.ext.asyncio import create_async_engine

conn = PostgresConnectionSettings(
    host="my-db",
    port=5432,
    database="orders",
    username="svc_user",
    password="s3cret",
)

# SQLAlchemy async engine — two equivalent forms:
engine = create_async_engine(conn.to_sqlalchemy_url())

# With pool settings included:
engine = create_async_engine(conn.to_sqlalchemy_url(), **conn.to_engine_kwargs())

From environment variables

POSTGRES_HOST=my-db
POSTGRES_PORT=5432
POSTGRES_DATABASE=orders
POSTGRES_USERNAME=svc_user
POSTGRES_PASSWORD=s3cret
conn = PostgresConnectionSettings.from_env()
engine = create_async_engine(conn.to_sqlalchemy_url(), **conn.to_engine_kwargs())

With TLS / SSL

from varco_core.connection import SSLConfig
from pathlib import Path

ssl = SSLConfig(
    ca_cert=Path("/etc/ssl/postgres-ca.pem"),
    verify=True,
)

conn = PostgresConnectionSettings.with_ssl(
    ssl,
    host="prod-db",
    database="orders",
    username="svc_user",
    password="s3cret",
)

# to_engine_kwargs() includes the ssl context inside connect_args automatically:
engine = create_async_engine(conn.to_sqlalchemy_url(), **conn.to_engine_kwargs())

Or from env:

POSTGRES_HOST=prod-db
POSTGRES_DATABASE=orders
POSTGRES_SSL__CA_CERT=/etc/ssl/postgres-ca.pem
POSTGRES_SSL__VERIFY=true

With mTLS (client certificates)

ssl = SSLConfig(
    ca_cert=Path("/etc/ssl/ca.pem"),
    client_cert=Path("/etc/ssl/client.crt"),
    client_key=Path("/etc/ssl/client.key"),
)

conn = PostgresConnectionSettings.with_ssl(ssl, host="prod-db", database="orders")

With structured auth object

from varco_core.connection import BasicAuthConfig

conn = PostgresConnectionSettings(
    host="prod-db",
    database="orders",
    auth=BasicAuthConfig(username="admin", password="s3cret"),
)
# auth overrides the inline username/password fields in to_dsn()

Or from env:

POSTGRES_AUTH__TYPE=basic
POSTGRES_AUTH__USERNAME=admin
POSTGRES_AUTH__PASSWORD=s3cret

Connection settings reference

Env var Default Description
POSTGRES_HOST localhost Database server hostname
POSTGRES_PORT 5432 Database server port
POSTGRES_DATABASE postgres Database name
POSTGRES_SCHEMA_NAME public Default search path schema
POSTGRES_USERNAME postgres Inline auth username
POSTGRES_PASSWORD (empty) Inline auth password
POSTGRES_POOL_SIZE 5 SQLAlchemy pool min connections
POSTGRES_MAX_OVERFLOW 10 SQLAlchemy pool max additional connections
POSTGRES_POOL_TIMEOUT 30.0 Seconds to wait for a pool connection
POSTGRES_SSL__CA_CERT Path to CA certificate
POSTGRES_SSL__CLIENT_CERT Path to client certificate (mTLS)
POSTGRES_SSL__CLIENT_KEY Path to client private key (mTLS)
POSTGRES_SSL__VERIFY true TLS peer verification
POSTGRES_AUTH__TYPE basic
POSTGRES_AUTH__USERNAME Auth username (overrides inline)
POSTGRES_AUTH__PASSWORD Auth password (overrides inline)

Related packages

Package Description
varco-core Domain model, service layer, query AST, JWT — required dependency
varco-beanie Beanie / Motor MongoDB backend (alternative to this package)

Migration 1.x → 2.0

SQLAlchemyRepositoryProvider.__init__ is now the DI-only path (it takes an injected SAConfig). Direct construction moved to a from_components() classmethod:

# Before (1.x)
provider = SQLAlchemyRepositoryProvider(base=Base, session_factory=sessions)

# After (2.0)
provider = SQLAlchemyRepositoryProvider.from_components(
    base=Base, session_factory=sessions
)

The DI path (container.get(SQLAlchemyRepositoryProvider) with an SAConfig bound) is unchanged.


Links

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

varco_sa-2.0.0.tar.gz (125.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

varco_sa-2.0.0-py3-none-any.whl (98.1 kB view details)

Uploaded Python 3

File details

Details for the file varco_sa-2.0.0.tar.gz.

File metadata

  • Download URL: varco_sa-2.0.0.tar.gz
  • Upload date:
  • Size: 125.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for varco_sa-2.0.0.tar.gz
Algorithm Hash digest
SHA256 b724d21d9b1f2cc9ad39216d30344c37ffcbcd854786465ce6254d91eef79693
MD5 1860b0adf57e990b36459d8901ce985a
BLAKE2b-256 ff346403281f6f3843c69653dd42e91aeb668a8b18e70d183b0a1c6e853774da

See more details on using hashes here.

File details

Details for the file varco_sa-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: varco_sa-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 98.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for varco_sa-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e1f1556d12dd46151b342d2adc0dd6491ef645dab9ceea21ff5b8d6f1a148600
MD5 8a3c1435d53383e070254a822a9aca97
BLAKE2b-256 c441433a4476fb4502db47bb4393e22df5c4aa10909445d80387577661216790

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page