Metadata-Version: 2.5
Name: orm-loader
Version: 3.0.0
Summary: Generic base classes to handle ORM functionality for multiple downstream datamodels
Project-URL: Homepage, https://AustralianCancerDataNetwork.github.io/orm-loader
Project-URL: Documentation, https://AustralianCancerDataNetwork.github.io/orm-loader
Project-URL: Repository, https://github.com/AustralianCancerDataNetwork/orm-loader
Project-URL: Issues, https://github.com/AustralianCancerDataNetwork/orm-loader/issues
Author-email: gkennos <georgina.kennedy@unsw.edu.au>
License: Apache-2.0
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Database :: Database Engines/Servers
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Requires-Python: >=3.12
Requires-Dist: chardet>=5.2.0
Requires-Dist: oa-configurator<3,>=2.1.0
Requires-Dist: pyarrow>=23.0.1
Requires-Dist: sqlalchemy>=2.0.45
Provides-Extra: dev
Requires-Dist: mkdocs-material>=9.7.7; extra == 'dev'
Requires-Dist: mkdocs-mermaid2-plugin; extra == 'dev'
Requires-Dist: mkdocs>=1.6.1; extra == 'dev'
Requires-Dist: mkdocstrings-python>=2.0.1; extra == 'dev'
Requires-Dist: oa-configurator[duckdb,postgres]<3,>=2.0.0; extra == 'dev'
Requires-Dist: pandas>=2.3.3; extra == 'dev'
Requires-Dist: pygments>=2.20.0; extra == 'dev'
Requires-Dist: pytest>=9.0.3; extra == 'dev'
Requires-Dist: python-dotenv; extra == 'dev'
Requires-Dist: requests>=2.33.0; extra == 'dev'
Requires-Dist: ruff>=0.14.11; extra == 'dev'
Requires-Dist: ty>=0.0.59; extra == 'dev'
Provides-Extra: duckdb
Requires-Dist: duckdb-sqlalchemy>=1.5; extra == 'duckdb'
Provides-Extra: postgres
Requires-Dist: psycopg[binary]>=3.2; extra == 'postgres'
Description-Content-Type: text/markdown

## orm-loader

[![CI](https://github.com/AustralianCancerDataNetwork/orm-loader/actions/workflows/ci.yml/badge.svg)](https://github.com/AustralianCancerDataNetwork/orm-loader/actions/workflows/ci.yml)

A lightweight foundation for building and validating SQLAlchemy-based data models.

`orm-loader` sits below any particular schema or CDM. It gives you a small set of reusable pieces for defining tables, loading files through staging tables, and checking models against external specifications. It stays out of domain logic on purpose.

The library focuses on:

* ORM table mixins and introspection
* staged file loading
* loader and validation infrastructure
* operational helpers that work across supported backends

The built-in backends are SQLite, PostgreSQL, and DuckDB. See [oa-configurator's supported dialects](https://AustralianCancerDataNetwork.github.io/oa-configurator/config-reference/#supported-dialects) for the dialect list this is built against.


### What this library provides

The package is deliberately small. Most downstream projects only need a couple of these pieces.

1. A minimal ORM table base

`ORMTableBase` provides structural utilities for mapped tables without pulling domain rules into the base layer.

It supports:
* mapper access and inspection
* primary key discovery
* required (non-nullable) column detection
* consistent primary key handling across models
* simple ID allocation helpers for sequence-less databases

```python
from orm_loader.tables import ORMTableBase

class MyTable(ORMTableBase, Base):
    __tablename__ = "my_table"

```
You can inherit from it directly or pick it up through one of the higher-level mixins.

2. File ingestion mixins

`FileLoadableTableInterface` adds staged file loading to ORM tables. Files are read with PyArrow on every backend, interpreted under a `ConversionPolicy`, and written to staging through each backend's bulk path.

Features include:
* staging table creation and cleanup
* files streamed in bounded batches, so memory does not grow with the row count
* optional conversion to column types and deduplication of the staging table
* backend-specific merge behaviour
* Arrow-based loading with a configurable conversion policy on PostgreSQL, DuckDB and SQLite
* delimited text (tab or comma delimiter, detected encoding) and Parquet input
* backend-aware index handling during merge

```python
class MyTable(FileLoadableTableInterface, ORMTableBase, Base):
    __tablename__ = "my_table"

```

The main extension points here are reader choice and the normal SQLAlchemy model definitions themselves. Most downstream projects do not need to override much beyond the model schema.

3. Structured serialisation and hashing

`SerialisableTableInterface` adds lightweight serialisation helpers for ORM rows.

It supports:
* conversion to dictionaries
* JSON serialisation
* stable row-level fingerprints
* iterator-style access to field/value pairs

```python
row = session.get(MyTable, 1)
row.to_dict()
row.to_json()
row.fingerprint()
```

This is useful for:

* debugging
* auditing
* reproducibility checks
* downstream APIs or exports


4. Model registry and validation scaffolding

The library includes validation infrastructure for comparing ORM models against external specifications.

This includes:
* a model registry
* table and field descriptors
* validator contracts
* a validation runner
* structured validation reports
Specifications can be loaded from CSV today, with support for other formats (e.g. LinkML) planned.

```python
registry = ModelRegistry(model_version="1.0")
registry.load_table_specs(table_csv, field_csv)
registry.register_models([MyTable])

runner = ValidationRunner(validators=always_on_validators())
report = runner.run(registry)
```

Validation output is available as:
* human-readable text
* structured dictionaries
* JSON (for CI/CD integration)
* exit codes suitable for pipelines

5. Database bootstrap helpers

The library provides lightweight helpers for schema creation and bootstrapping. It does not try to replace migrations.

```python
from orm_loader.metadata import Base
from orm_loader.bootstrap import bootstrap

bootstrap(engine, create=True)
```

6. Bulk-loading helpers

There are a few lower-level helpers for trusted bulk workflows, including backend-aware foreign key management and SQLite connection setup for heavy local loads.

## Summary

This library is meant to be the boring layer underneath downstream models:

* reusable ORM mixins
* staged ingestion patterns
* validation scaffolding
* operational helpers

Domain rules, business logic, and schema semantics stay in the downstream project.

This makes it suitable as a shared foundation for:
* clinical data models
* research data marts
* registry schemas
* synthetic data pipelines
