from sqlalchemy import Integer, String, create_engine, select, text
from sqlalchemy.orm import DeclarativeBase, Mapped, Session, mapped_column


class Base(DeclarativeBase):
    pass


class Order(Base):
    __tablename__ = "orders"
    id: Mapped[int] = mapped_column(primary_key=True)
    customer: Mapped[str] = mapped_column(String(80))
    total_cents: Mapped[int] = mapped_column(Integer)


engine = create_engine("sqlite+pysqlite:///:memory:")
Base.metadata.create_all(engine)
with Session(engine) as session:
    session.add_all([
        Order(customer="ana", total_cents=1200),
        Order(customer="ana", total_cents=800),
        Order(customer="luis", total_cents=300),
    ])
    session.commit()
    statement = select(Order.id, Order.total_cents).where(
        Order.customer == "ana"
    ).order_by(Order.id)
    orm_rows = session.execute(statement).all()
    sql_rows = session.execute(text(
        "SELECT id, total_cents FROM orders "
        "WHERE customer = :customer ORDER BY id"
    ), {"customer": "ana"}).all()
    assert orm_rows == sql_rows == [(1, 1200), (2, 800)]
    injected = "ana' OR 1=1 --"
    assert session.execute(text(
        "SELECT id FROM orders WHERE customer = :customer"
    ), {"customer": injected}).all() == []
    plan = session.execute(text(
        "EXPLAIN QUERY PLAN SELECT id, total_cents FROM orders "
        "WHERE customer = :customer ORDER BY id"
    ), {"customer": "ana"}).all()
    print("SQL:", statement.compile(engine))
    print("PLAN:", plan)
    print("OK: ORM and SQL agree; parameters remain data")
engine.dispose()
