Skip to main content

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.

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-1.5.5.tar.gz (17.4 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-1.5.5-py3-none-any.whl (19.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: iron_sql-1.5.5.tar.gz
  • Upload date:
  • Size: 17.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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-1.5.5.tar.gz
Algorithm Hash digest
SHA256 adfce6d45480a8e6af3cc39e4a26c8c7fe302f3491cff683b6c72321ba33ab5e
MD5 397e7c2464cefe5f73205ce405a1d1ba
BLAKE2b-256 ba118437694eeb032882673f53bf2cb973fcc56bac59c4f8dff7982a9d07ce7a

See more details on using hashes here.

File details

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

File metadata

  • Download URL: iron_sql-1.5.5-py3-none-any.whl
  • Upload date:
  • Size: 19.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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-1.5.5-py3-none-any.whl
Algorithm Hash digest
SHA256 28a0c1c04d8bacb2619a50b241f5520b3ecbe88ae7568231b3db1b08005c1847
MD5 5137490905d7bc1bfd608616968a06fc
BLAKE2b-256 bf121c900f8bf1278bc1bd74791ad5f5c8809dfd7f12945a448899d80e220415

See more details on using hashes here.

Release history Release notifications | RSS feed

1.5.6

2 files

This release

1.5.5 This release

2 files

0.5.4

2 files

0.5.3

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.6

2 files

0.4.5

2 files

0.4.4

2 files

0.4.3

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.0

2 files

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

Supported by

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