( Database layer )

A TypeORM-style ORM for Python

austial.orm is a TypeORM-shaped data-mapper ORM that plugs into Austial's dependency injection. Entities are plain objects, repositories are injected by type, and schema changes are versioned with Alembic.

Entities as plain objects

Declare an entity with @Entity() and mark columns with markers such as Column() and PrimaryGeneratedColumn(). There is no active-record magic, no lazy proxies and no dirty checking: instances are ordinary mutable objects.

from austial.orm import Column, Entity, PrimaryGeneratedColumn


@Entity()
class Cat:
    id: int = PrimaryGeneratedColumn()
    name: str = Column()
    age: int = Column(nullable=True)

Repositories injected by type

Register entities in the feature module that owns them, then inject a Repository for the entity into any provider.

from austial import Injectable
from austial.orm import InjectRepository, Repository


@Injectable()
class CatsService:
    def __init__(self, repository: Repository[Cat] = InjectRepository(Cat)):
        self.repository = repository

    async def create(self, name: str) -> Cat:
        return await self.repository.save(Cat(name=name))

    async def find_all(self) -> list[Cat]:
        return await self.repository.find()

Relations, query builder and transactions

OneToOne, OneToMany, ManyToOne and ManyToMany relations are supported. For anything the find options cannot express, a fluent query builder takes a SQL fragment and a separate dictionary of bound parameters, so values are never string-formatted into the query.

Databases and migrations

PostgreSQL (through asyncpg) and SQLite (through aiosqlite) are supported today behind a pluggable driver interface. SQLAlchemy Core is used internally for SQL compilation and connection pooling, and you never import it in application code. austial.migrations wires Alembic to the same data source, so you can generate and apply migrations without leaving the framework.

OrmModule.for_root(
    type_="postgres",
    url="postgresql+asyncpg://user:pass@localhost/mydb",
    entities=[Cat],
)
Zero-config local development can use type_="sqlite" instead

Frequently asked questions

Is austial.orm built on SQLAlchemy?

It is its own data-mapper API. SQLAlchemy Core is used internally for SQL compilation and connection pooling behind a driver interface, and it does not appear in application code.

Which databases are supported?

PostgreSQL through asyncpg and SQLite through aiosqlite. The driver interface is pluggable, and the docs describe how to swap in a different database.

Is the query builder safe from SQL injection?

WHERE clauses are written as a SQL fragment plus a separate bound-parameter dictionary, and values only ever reach the database through the driver's parameter binding.

Go deeper in the docs

( Keep reading )

( Click. Copy. Build. )

Seeing “command not found”? Run uv tool update-shell, then open a new terminal. Details