SQLAlchemy

One common use of chide is for creating sample objects and making assertions about database table contents when using SQLAlchemy. As a result, there are specialised implementations included to make life easier that are described below.

Sets

chide has a special Set subclass that helps to make sure only one sample object is created with a particular primary key in any one table.

For example, given these two models:

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    child_id = Column(Integer, ForeignKey('child.id'))
    child = relationship('Child')

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    value = Column(Integer)

We can set up a collection of sample values as follows:

from chide import Collection, nest

samples = Collection({
    Parent: {'id': 1, 'child': nest(Child)},
    Child: {'id': 3, 'value': 42}
})

Now we can quickly make sample objects and add them to a session:

>>> session = Session()
>>> session.add(samples.make(Parent))
>>> session.commit()

This gives us a parent and a child:

>>> session.query(Parent).one()
<Parent ...>
>>> _.child
<Child ...>

If we create multiple parent objects and don’t want to have to worry about clashing children being created by mistake, we can use a chide.sqlalchemy.Set to make sure that we only have one sample object with a given primary key at any time:

>>> from chide.sqlalchemy import Set
>>> current_samples = Set(samples)
>>> session = Session()
>>> session.add(current_samples.get(Parent, id=1))
>>> session.add(current_samples.get(Parent, id=2))
>>> session.commit()

This gives us two parents that both point to the same child:

>>> parent1 = session.query(Parent).filter_by(id=1).one()
>>> parent2 = session.query(Parent).filter_by(id=2).one()
>>> parent1.child is parent2.child
True

Of course, if we want different children, that’s easy too:

>>> session = Session()
>>> session.add(current_samples.get(Parent, id=3, child=Child(value=6)))
>>> session.add(current_samples.get(Parent, id=4, child=Child(value=7)))
>>> session.commit()

The children’s primary keys will be created by the database, but the values are as we need them:

>>> parent3 = session.query(Parent).filter_by(id=3).one()
>>> parent3.child.value
6
>>> parent4 = session.query(Parent).filter_by(id=4).one()
>>> parent4.child.value
7

Row Simplifier

For a table such as this:

from sqlalchemy import MetaData, Table, Column, Integer, String

metadata = MetaData()

user_table = Table(
    "user_account",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("name", String(30)),
    Column("fullname", String),
)

A simplifier is included for the rows returned by a query such as this:

with engine.connect() as conn:
    rows = conn.execute(select(user_table))

It is used as follows:

>>> from chide.sqlalchemy import RowSimplifier
>>> for attrs in RowSimplifier().many(rows):
...     print(attrs)
{'id': 1, 'name': 'sandy', 'fullname': 'Sandy Cheeks'}
{'id': 2, 'name': 'patrick', 'fullname': 'Patrick Star'}

ORM-Mapped Object Simplifier

For an ORM-mapped objects such as this:

from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "user_account"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    fullname: Mapped[str | None]

A simplifier is included that can be used to simplify the results of a query such as this:

with Session(engine) as session:
    objects = session.query(User)

It is used as follows:

>>> from chide.sqlalchemy import MappedSimplifier
>>> for attrs in MappedSimplifier().many(objects):
...     print(attrs)
{'id': 1, 'name': 'squidward', 'fullname': 'Squidward Tentacles'}
{'id': 2, 'name': 'ehkrabs', 'fullname': 'Eugene H. Krabs'}