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],
)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.