# slymit/sa-filters architecture

> Architecture diagram of the GitHub repository slymit/sa-filters, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-01). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/slymit/sa-filters
- Repository: https://github.com/slymit/sa-filters

## Overview

#### Purpose and Public API
`sa-filters` is a Python library that transforms SQLAlchemy ORM `Select` and legacy `Query` objects for API-facing filtering, sorting, restricted column loading, and pagination. Its package-level API is exposed through `sa_filters/__init__.py`; primary transformation entry points are implemented in `sa_filters/filters.py`, `sa_filters/sorting.py`, `sa_filters/loads.py`, and `sa_filters/pagination.py`.

#### Statement/Model Resolution Boundary
The library accepts declarative specification dictionaries rather than HTTP requests or database connections. It resolves requested models, table names, fields, and query participants against the input SQLAlchemy statement, including statements selecting columns, functions, or explicit `select_from` clauses. Shared ORM/query introspection and model resolution are centralized in `sa_filters/models.py`; invalid specifications surface through `sa_filters/exceptions.py`.

#### Filter Compilation
`apply_filters` converts sequential filter specs into SQLAlchemy predicates and returns a new statement/query. `sa_filters/filters.py` supports comparison, null, membership, pattern, and PostgreSQL ARRAY operators, plus nested `and`, `or`, and `not` expression groups. Fields may be mapped columns or SQLAlchemy hybrid properties/methods. This is a compilation layer: caller-provided dicts become ORM expressions, while SQL generation and execution remain SQLAlchemy’s responsibility.

#### Automatic Relationship Joining
Filtering and sorting can target models not already present in the input statement. The component detects model-targeted criteria and asks SQLAlchemy to add an implicit join when relationship/foreign-key metadata makes the join condition inferable. This behavior is shared conceptually by `sa_filters/filters.py`, `sa_filters/sorting.py`, and model inspection in `sa_filters/models.py`; callers can disable it for an explicit query-shape boundary.

#### Sort Compilation
`apply_sort` applies ordered `ORDER BY` clauses from model/field/direction specs in `sa_filters/sorting.py`. It supports ascending/descending ordering, hybrid attributes, optional automatic joins, and database-dependent `NULLS FIRST`/`NULLS LAST` modifiers. SQLAlchemy and the selected RDBMS determine final dialect compatibility.

#### Restricted ORM Loads
`apply_loads` in `sa_filters/loads.py` translates per-model field allowlists into SQLAlchemy deferred-load options. It constrains normally loaded columns, but does not control fields introduced by joined eager-loading semantics; those remain an explicit caller-side SQLAlchemy loader-option concern. Model discovery is coordinated with `sa_filters/models.py`.

#### Pagination and Execution Ownership
`apply_pagination` in `sa_filters/pagination.py` applies page offset/limit and returns both the transformed statement and pagination metadata. The caller supplies `total_results`, so count-query construction and all execution (`Session.execute`, `Session.scalar`, or legacy query evaluation) stay outside the library. This keeps pagination independent of session lifecycle and result materialization.

#### Runtime and Compatibility
Runtime dependencies are Python plus SQLAlchemy 1.4/2.0, declared in `pyproject.toml`. The library is database-agnostic across tested SQLite, MySQL, and PostgreSQL, with PostgreSQL-specific ARRAY filtering and dialect-sensitive null ordering. CI is defined in `.github/workflows/ci.yml`; database integration behavior is validated against ORM fixtures and interface tests under `test/`.

Main entry points: [`sa_filters/filters.py`](https://github.com/slymit/sa-filters/blob/main/sa_filters/filters.py) (Filter compiler), [`sa_filters/sorting.py`](https://github.com/slymit/sa-filters/blob/main/sa_filters/sorting.py) (Sort compiler), [`sa_filters/loads.py`](https://github.com/slymit/sa-filters/blob/main/sa_filters/loads.py) (Load restriction compiler), [`sa_filters/__init__.py`](https://github.com/slymit/sa-filters/blob/main/sa_filters/__init__.py) (Package exports)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_public_api["Public API"]
  node_package_api["Package exports<br/>Python API<br/>[__init__.py]"]
  node_runtime_dependencies["Runtime dependencies<br/>package metadata<br/>[pyproject.toml]"]
end

subgraph group_compilation["Statement Transformations"]
  node_filters["Filter compiler<br/>apply_filters<br/>[filters.py]"]
  node_sorting["Sort compiler<br/>apply_sort<br/>[sorting.py]"]
  node_loads["Load restriction compiler<br/>apply_loads<br/>[loads.py]"]
  node_pagination["Pagination transformer<br/>apply_pagination<br/>[pagination.py]"]
  node_orm_expressions["ORM predicates and options<br/>compiled expressions"]
end

subgraph group_resolution["ORM Resolution"]
  node_model_resolution["Statement/model inspection<br/>ORM introspection<br/>[models.py]"]
  node_exceptions["Specification errors<br/>exceptions<br/>[exceptions.py]"]
end

subgraph group_external["External Ownership"]
  node_caller(("API caller<br/>consumer"))
  node_sqlalchemy_statement["Select or legacy Query<br/>input statement"]
  node_declarative_specs["Filter, sort, load specs<br/>input dictionaries"]
  node_transformed_statement["Transformed statement<br/>output statement/query"]
  node_sqlalchemy_orm{{"SQLAlchemy ORM<br/>dependency"}}
  node_database[("Selected RDBMS<br/>database")]
  node_caller_execution["Caller count and execution<br/>execution boundary"]
  node_ci["CI matrix<br/>workflow<br/>[ci.yml]"]
end

node_caller -->|"imports"| node_package_api
node_caller -->|"provides"| node_sqlalchemy_statement
node_caller -->|"provides"| node_declarative_specs
node_package_api -->|"exports"| node_filters
node_package_api -->|"exports"| node_sorting
node_package_api -->|"exports"| node_loads
node_package_api -->|"exports"| node_pagination
node_declarative_specs -->|"filter specs"| node_filters
node_declarative_specs -->|"sort specs"| node_sorting
node_declarative_specs -->|"load allowlists"| node_loads
node_sqlalchemy_statement -->|"input"| node_filters
node_sqlalchemy_statement -->|"input"| node_sorting
node_sqlalchemy_statement -->|"input"| node_loads
node_sqlalchemy_statement -->|"input"| node_pagination
node_filters -->|"resolves criteria targets"| node_model_resolution
node_sorting -->|"resolves ordering targets"| node_model_resolution
node_loads -->|"discovers models"| node_model_resolution
node_model_resolution -->|"rejects invalid specs"| node_exceptions
node_filters -->|"predicates"| node_orm_expressions
node_sorting -->|"order clauses"| node_orm_expressions
node_loads -->|"loader options"| node_orm_expressions
node_orm_expressions -->|"applied through"| node_sqlalchemy_orm
node_filters -->|"returns"| node_transformed_statement
node_sorting -->|"returns"| node_transformed_statement
node_loads -->|"returns"| node_transformed_statement
node_pagination -->|"returns statement and metadata"| node_transformed_statement
node_sqlalchemy_orm -->|"generates dialect SQL"| node_database
node_transformed_statement -->|"caller executes"| node_caller_execution
node_caller_execution -->|"session execution"| node_sqlalchemy_orm
node_runtime_dependencies -->|"requires"| node_sqlalchemy_orm
node_ci -.->|"tests integration"| node_database

click node_package_api "https://github.com/slymit/sa-filters/blob/main/sa_filters/__init__.py"
click node_filters "https://github.com/slymit/sa-filters/blob/main/sa_filters/filters.py"
click node_sorting "https://github.com/slymit/sa-filters/blob/main/sa_filters/sorting.py"
click node_loads "https://github.com/slymit/sa-filters/blob/main/sa_filters/loads.py"
click node_pagination "https://github.com/slymit/sa-filters/blob/main/sa_filters/pagination.py"
click node_model_resolution "https://github.com/slymit/sa-filters/blob/main/sa_filters/models.py"
click node_exceptions "https://github.com/slymit/sa-filters/blob/main/sa_filters/exceptions.py"
click node_runtime_dependencies "https://github.com/slymit/sa-filters/blob/main/pyproject.toml"
click node_ci "https://github.com/slymit/sa-filters/blob/main/.github/workflows/ci.yml"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_package_api,node_runtime_dependencies toneBlue
class node_filters,node_sorting,node_loads,node_pagination,node_orm_expressions toneAmber
class node_model_resolution,node_exceptions toneMint
class node_caller,node_sqlalchemy_statement,node_declarative_specs,node_transformed_statement,node_sqlalchemy_orm,node_database,node_caller_execution,node_ci toneRose
```

## Components

### Public API

- [Package exports](https://github.com/slymit/sa-filters/blob/main/sa_filters/__init__.py): Python API · `sa_filters/__init__.py`
- [Runtime dependencies](https://github.com/slymit/sa-filters/blob/main/pyproject.toml): package metadata · Declares Python and SQLAlchemy 1.4/2.0 support. · `pyproject.toml`

### Statement Transformations

- [Filter compiler](https://github.com/slymit/sa-filters/blob/main/sa_filters/filters.py): apply_filters · Compiles nested filter specifications into predicates. · `sa_filters/filters.py`
- [Sort compiler](https://github.com/slymit/sa-filters/blob/main/sa_filters/sorting.py): apply_sort · Builds ordered clauses and null-order modifiers. · `sa_filters/sorting.py`
- [Load restriction compiler](https://github.com/slymit/sa-filters/blob/main/sa_filters/loads.py): apply_loads · Converts model field allowlists to deferred-load options. · `sa_filters/loads.py`
- [Pagination transformer](https://github.com/slymit/sa-filters/blob/main/sa_filters/pagination.py): apply_pagination · Applies offset and limit and returns metadata. · `sa_filters/pagination.py`
- **ORM predicates and options**: compiled expressions

### ORM Resolution

- [Statement/model inspection](https://github.com/slymit/sa-filters/blob/main/sa_filters/models.py): ORM introspection · Resolves models, tables, fields, and statement participants. · `sa_filters/models.py`
- [Specification errors](https://github.com/slymit/sa-filters/blob/main/sa_filters/exceptions.py): exceptions · Reports invalid declarative specifications. · `sa_filters/exceptions.py`

### External Ownership

- **API caller**: consumer · Supplies SQLAlchemy statements and declarative specs.
- **Select or legacy Query**: input statement
- **Filter, sort, load specs**: input dictionaries
- **Transformed statement**: output statement/query
- **SQLAlchemy ORM**: dependency · Infers joins, generates SQL, and executes only when called by the consumer.
- **Selected RDBMS**: database · Determines dialect compatibility and null-order behavior.
- **Caller count and execution**: execution boundary · Owns total counts, sessions, and result materialization.
- [CI matrix](https://github.com/slymit/sa-filters/blob/main/.github/workflows/ci.yml): workflow · Validates supported database integration behavior. · `.github/workflows/ci.yml`

## Connections

- API caller → Package exports: imports
- API caller → Select or legacy Query: provides
- API caller → Filter, sort, load specs: provides
- Package exports → Filter compiler: exports
- Package exports → Sort compiler: exports
- Package exports → Load restriction compiler: exports
- Package exports → Pagination transformer: exports
- Filter, sort, load specs → Filter compiler: filter specs
- Filter, sort, load specs → Sort compiler: sort specs
- Filter, sort, load specs → Load restriction compiler: load allowlists
- Select or legacy Query → Filter compiler: input
- Select or legacy Query → Sort compiler: input
- Select or legacy Query → Load restriction compiler: input
- Select or legacy Query → Pagination transformer: input
- Filter compiler → Statement/model inspection: resolves criteria targets
- Sort compiler → Statement/model inspection: resolves ordering targets
- Load restriction compiler → Statement/model inspection: discovers models
- Statement/model inspection → Specification errors: rejects invalid specs
- Filter compiler → ORM predicates and options: predicates
- Sort compiler → ORM predicates and options: order clauses
- Load restriction compiler → ORM predicates and options: loader options
- ORM predicates and options → SQLAlchemy ORM: applied through
- Filter compiler → Transformed statement: returns
- Sort compiler → Transformed statement: returns
- Load restriction compiler → Transformed statement: returns
- Pagination transformer → Transformed statement: returns statement and metadata
- SQLAlchemy ORM → Selected RDBMS: generates dialect SQL
- Transformed statement → Caller count and execution: caller executes
- Caller count and execution → SQLAlchemy ORM: session execution
- Runtime dependencies → SQLAlchemy ORM: requires
- CI matrix → Selected RDBMS: tests integration
