Skip to content

SQLAlchemy

The SQLAlchemy adaptor reads a Table or a declarative mapped class, and its members are dicts (for a Table) or instances of the class. What the metadata spells plainly is read into the neutral model and checked there first; everything else is left to the database, which decides by inserting the record into an in-memory SQLite database built from the table's own DDL, so a CHECK constraint the neutral model cannot read still decides membership. A mapped class that is also a dataclass (MappedAsDataclass) goes to this adaptor, not the dataclass one. It needs SQLAlchemy 2.0 or later, pip install "mathema-language[sqlalchemy]", and is tested at 2.0 and at the latest release.

What it reads

SQLAlchemy spelling Neutral model Notes
Integer, SmallInteger, BigInteger int of 32, 16, 64 bits
Float, Numeric(p, s) float, decimal(p, s)
String(n), Text string, max_len n a lone surrogate is not a member, since SQLite cannot encode it
Boolean, Date, Time, DateTime, Interval, LargeBinary the matching base type a timezone-aware DateTime is UTC
Enum(...) a categorical
nullable=False not nullable
an autoincrement primary key, a default, a server default not required
CheckConstraint("quantity BETWEEN 1 AND 100"), "unit_price >= 0", on the table or on a column min, max and the exclusive bounds plain comparisons and BETWEEN only
any other CheckConstraint not read decided by the database
unique=True, UniqueConstraint, ForeignKey not checked on a single record uniqueness and keys are facts about many records, not one

A worked claim

The shop's orders table, from examples/shop/db.py:

import sqlalchemy as sa
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column


class Base(DeclarativeBase):
    pass


class Order(Base):
    __tablename__ = "orders"
    id: Mapped[int] = mapped_column(primary_key=True)
    sku: Mapped[str] = mapped_column(sa.String(12), sa.CheckConstraint("length(sku) >= 3"))
    quantity: Mapped[int] = mapped_column(sa.CheckConstraint("quantity BETWEEN 1 AND 100"))
    unit_price: Mapped[Decimal] = mapped_column(sa.Numeric(10, 2),
                                                sa.CheckConstraint("unit_price >= 0"))


def order_total(order: Order) -> Decimal:
    """What the customer pays for the order."""
    return order.quantity * order.unit_price
Function Claim Verdict Why
order_total for order in L[shop.db.Order], f(order) >= 0 proven The lift reads both bounds off the CHECK constraints, a quantity of at least one times a price of at least zero.
order_total for order in L[shop.db.Order], f(order) <= 10000 falsified Nothing bounds the price from above.

Enforcing the schema

A function that guards a boundary should refuse a record its schema rejects. excluded_outside_domain feeds it records just outside the language, and the witness names the value and why it is outside, in the library's own words. This function trusts its input, so a record the schema rejects goes straight through:

def receipt_line(order: Order) -> str:
    """The line an order prints on the receipt."""
    return f"{order.quantity} x {order.sku}"
f = receipt_line
for order in L[shop.db.Order], excluded_outside_domain(order)
    falsified   order = Order(id=2147483648, sku='', quantity=1, unit_price=Decimal('0')) (outside L[shop.db.Order] at .id: int32)

The same claim over the function that loads the record, from a request or a database, is the one that should hold.