ORMatic Overview#
ORMatic is a subpackage of KRROOD designed to integrate Python dataclasses with the SQLAlchemy ORM. It operates by generating a SQLAlchemy declarative model layer, offering utilities for translating between domain objects (dataclasses) and database representations (rows).
This approach promotes a separation between the domain model and the persistence mechanism, allowing developers to concentrate on business logic while abstracting underlying database implementation and SQLAlchemy specifics.
Core Assumptions and Modeling Rules#
To ensure unambiguous translation and an ergonomic generated ORM, ORMatic adheres to the following rules for dataclass modeling:
Protected Fields: Any dataclass field name beginning with
_is ignored for persistence. These protected fields are suitable for transient or derived runtime data.Optional Types: The only supported union is
Optional[T]. Other unions should be modeled using a shared superclass.Collections: Iterables must be non-optional and non-nested. For an “optional list,” use a default factory that returns an empty collection.
Inheritance and Polymorphism: Inheritance is supported and generates joined-table inheritance. Note that only the first base class in a multiple inheritance structure is considered for queries using abstract classes.
Type Discipline: Dataclass fields require concrete, non-ambiguous type annotations. Prefer small dataclasses or value objects over primitive types when modeling relationships.
When dataclasses cannot conform to these patterns, the following alternatives are available:
Alternative Mapping: Explicit mapping classes can be provided to control how a dataclass is persisted.
Type Decorator: Custom type decorators can be supplied for specialized value types.
Detailed information on these options is provided in the Dealing with unmappable dataclasses section.
What ORMatic Generates#
Execution of ORMatic on a set of classes produces a module containing:
Base: An SQLAlchemyDeclarativeBasethat manages metadata and atype_mappingsregistry for custom types.*DAOClasses: One class per dataclass (and per explicit mapping). Each is a SQLAlchemy declarative model that includes: - Columns for fields with built-in or custom types - Foreign keys and relationships inferred from nested dataclasses and collections -__mapper_args__for inheritance and polymorphic configuration
ORMatic analyzes the dataclass structure to identify scalar fields, one-to-one, one-to-many, and many-to-many associations. This information is then used to generate a full, decoupled SQLAlchemy declarative layer via a Jinja template.
Persisting Objects#
krrood.ormatic.dao.to_dao(): Converts a dataclass instance into its corresponding DAO object, including recursive conversion of nested elements.krrood.ormatic.dao.DataAccessObject.from_dao(): Converts a loaded DAO instance back into the original dataclass, including nested components and collections.