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={"float8": "decimal.Decimal"} maps database type names to Python type strings. For built-in types the key is the PostgreSQL internal name (float8, varchar, timestamptz), not the SQL-standard spelling (double precision, character varying); for a user-defined enum, domain or extension type it is the type name as declared (custom_int, citext). A key that no query column or parameter uses raises ValueError listing the type names actually in use.
  • 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/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.
  • A user-defined type may reuse a standard SQL spelling of a built-in (integer, real). Enums and composite types are recognised as user-defined either way. A domain or extension type is recognised only where the column references it schema-qualified (v public."integer"), because an unqualified reference reaches iron_sql spelled exactly like the built-in; such a column resolves to the built-in, and type_overrides cannot name it.

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.6.tar.gz (19.1 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.6-py3-none-any.whl (21.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: iron_sql-1.5.6.tar.gz
  • Upload date:
  • Size: 19.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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.6.tar.gz
Algorithm Hash digest
SHA256 cb388d66a74b7a5854a897305ac2e3c900a68e5beca8d709c19ad399a5958c23
MD5 cb642cd957dbd229f328f87c35222fab
BLAKE2b-256 6b1e7432510e39793ee9e8202cf88f1c322299080f3a53b60e0c2b2952bf21a1

See more details on using hashes here.

File details

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

File metadata

  • Download URL: iron_sql-1.5.6-py3-none-any.whl
  • Upload date:
  • Size: 21.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","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.6-py3-none-any.whl
Algorithm Hash digest
SHA256 24f46a7f45095474faeb22aedd405442150e77328771713bb079454f140f261f
MD5 9bbba2bdda22353dfc169de80ef66053
BLAKE2b-256 588cf328fcc526b947ad17cfa20ce0d2b837ee8fbe85b66bd29b6a6f0dd7d95a

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.5.6 This release

2 files

1.5.5

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