Skip to main content

iron_sql generates typed async PostgreSQL clients and runtime helpers from schemas and SQL queries

Project description

iron_sql

License main PyPI - Version

iron_sql is a typed SQL code generator and async runtime for PostgreSQL. Write SQL where you use it, run generate_sql_module, and get a module with typed dataclasses, query helpers, and pooled connections without hand-written boilerplate.

Installation

pip install iron-sql             # runtime only (psycopg + psycopg-pool + pydantic)
pip install iron-sql[codegen]    # + inflection for code generation

The sqlc binary is bundled automatically via the sqlc Python package.

Key Features

  • Query discovery. generate_sql_module scans your codebase for calls like <module>_sql("SELECT ..."), runs sqlc for type analysis, and emits a typed module.
  • Strong typing. Generated dataclasses and method signatures flow through your IDE and type checker.
  • Async runtime. Built on psycopg v3 with pooled connections, context-based connection reuse, and transaction helpers.
  • Streaming. query_stream() uses server-side cursors for memory-efficient iteration over large result sets.
  • Safe by default. Helper methods enforce expected row counts instead of returning silent None.

Package Layout

  • runtime.py -- async ConnectionPool, row helpers (get_one_row, typed_scalar_row), JSON validation decorators.
  • codegen/generator.py -- query discovery, type resolution, module rendering.
  • codegen/sqlc.py -- wraps the sqlc CLI and models its JSON output.
  • codegen/util.py -- shared codegen utilities (indent_block, write_if_changed).

Getting Started

  1. Add a schema file. A Postgres DDL dump, e.g. db/schema.sql.
  2. Write queries where they live. Import the future helper and use SQL literals inline:
    from myapp.db.mydb import mydb_sql
    
    user = await mydb_sql(
        "SELECT id, username, email, created_at FROM users WHERE id = @user_id"
    ).query_single_row(user_id=uid)
    
    Named parameters use @param (required) or @param? (optional, expands to sqlc.narg). Positional $1 works too.
  3. Generate the client module.
    from pathlib import Path
    
    from iron_sql.codegen import generate_sql_module
    
    generate_sql_module(
        schema_path=Path("schema.sql"),
        module_full_name="myapp.db.mydb",
        dsn_expr="myapp.config:DSN",
        src_path=Path("."),
    )
    
    This writes myapp/db/mydb.py containing:
    • a connection pool singleton,
    • *_connection() and *_transaction() context managers,
    • *_listen_session(channel) and *_notify(channel, payload="") helpers,
    • dataclasses for multi-column results (deduplicated by table),
    • StrEnum classes for PostgreSQL enums,
    • a query class per statement with typed methods,
    • overloads for the *_sql() helper so editors infer return types.

Customization

  • Type overrides. type_overrides={"custom_type": "int"} maps database type names to Python type strings.
  • JSON model overrides. json_model_overrides={"users.metadata": "myapp.models:UserMeta"} adds Pydantic validation for JSON/JSONB columns.
  • Naming conventions. Supply to_pascal_fn and to_snake_fn callables to control generated names.
  • Connection settings. dsn_expr and pool_options_expr are written verbatim into the generated module; point them at config variables, env var lookups, or function calls.
  • Debug artifacts. Pass debug_path to save sqlc inputs and outputs for inspection.

Runtime Highlights

  • ConnectionPool opens lazily and reopens after close(), with ContextVar-based connection reuse for nested contexts.
  • *_listen_session() uses a dedicated pooled connection and doesn't reuse ContextVar transaction connections.
  • query_single_row() raises NoRowsError; query_optional_row() returns None. Both raise TooManyRowsError on 2+ rows.
  • query_stream() returns an async context manager yielding an AsyncGenerator; uses server-side cursors with automatic transaction management.
  • JSONB params are sent with psycopg.types.json.Jsonb; JSON with psycopg.types.json.Json. Scalar row factories validate types at runtime.
  • json_validated decorator applies Pydantic model validation to dataclass fields on construction.

Example

The example/ directory contains a complete working setup: a PostgreSQL schema, generation script with testcontainers, and sample query definitions. See example/generate.py for the codegen call and example/myapp/main.py for query usage.

Validation and Troubleshooting

  • Errors identify the file and line where the problematic statement lives.
  • Unknown SQL types map to object and emit UnknownSQLTypeWarning (promotable to error with warnings.filterwarnings).
  • Statements with the same SQL but conflicting row_type values are rejected at generation time.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

iron_sql-0.5.3.tar.gz (16.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

iron_sql-0.5.3-py3-none-any.whl (18.5 kB view details)

Uploaded Python 3

File details

Details for the file iron_sql-0.5.3.tar.gz.

File metadata

  • Download URL: iron_sql-0.5.3.tar.gz
  • Upload date:
  • Size: 16.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for iron_sql-0.5.3.tar.gz
Algorithm Hash digest
SHA256 abee2207fea3eba944ed7571be4207e7f45b7f4eda6a887046b37a98e9c2a508
MD5 47c5a2c6d75b360c3285e02e7a87d99a
BLAKE2b-256 d1271869c9bc87a405a06b07047a6ea286634d624510aec4be01668c0d0503a8

See more details on using hashes here.

File details

Details for the file iron_sql-0.5.3-py3-none-any.whl.

File metadata

  • Download URL: iron_sql-0.5.3-py3-none-any.whl
  • Upload date:
  • Size: 18.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for iron_sql-0.5.3-py3-none-any.whl
Algorithm Hash digest
SHA256 fc0cb4717db7ef289c7755d35306d5abb45d65761bcfada6ab2fe044112e5ba9
MD5 eaa6a82344cfe77aebdd8210e0a28b28
BLAKE2b-256 9d84c24ebbe3126bf66ffc83fe3a1c11992e83c1dd991e4d64014add89a8140f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page