Hi,
I spent some more time to improve support for SA 2 of one of my SA-based
libraries[1] (the most ancient one, born with SA 0.5, fifteen years ago!):
its goal is to provide a layer that made it easier to "expose" a SA
query (either an ORM one or a Core select()) thru a web service,
handling particular arguments to apply different kind of "refinements"
such as ordering and filtering.
One of the tests that exercise the "ordering" refinements fails, and I
could not understand what is going wrong nor find a workaround.
The following simple script builds an ORM query and prints its SQL:
import sqlalchemy as sa
SQLALCHEMY_VERSION = tuple(int(p) if p.isdigit() else p for p in sa.__version__.split('.'))
metadata = sa.MetaData()
if SQLALCHEMY_VERSION > (2, 0):
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
metadata = metadata
else:
from sqlalchemy.orm import declarative_base
Base = declarative_base(metadata=metadata)
class Person(Base):
__tablename__ = 'persons'
id = sa.Column(sa.Integer, primary_key=True)
firstname = sa.Column(sa.String)
class Pet(Base):
__tablename__ = 'pets'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String)
person_id = sa.Column(sa.Integer, sa.ForeignKey('
persons.id'))
person = sa.orm.relationship(Person, backref=sa.orm.backref('pets', order_by=id))
engine = sa.create_engine('sqlite:///:memory:')
Session = sa.orm.sessionmaker(bind=engine)
metadata.create_all(engine)
query = sa.orm.Query([Pet]).options(sa.orm.joinedload(Pet.person).load_only(Person.firstname))
print(str(query))
It emits the following output under both SA 1.4 and SA 2.0:
SELECT
pets.id AS pets_id,
pets.name AS pets_name, pets.person_id AS pets_person_id,
persons_1.id AS persons_1_id, persons_1.firstname AS persons_1_firstname
FROM pets LEFT OUTER JOIN persons AS persons_1 ON
persons_1.id = pets.person_id
And now the problem: in short, when the library is asked to apply an
"order by" on some column(s), it uses an utility function[2] to find a
column given it's name in the particular query, and then it applies an
`order_by()` the original query[3].
So, appending the following lines to the script above:
from metapensiero.sqlalchemy.proxy.utils import col_by_name
col = col_by_name(query.statement, 'firstname')
sorted_query = query.order_by(col)
print(str(sorted_query))
I get the following, expected, output under SA 1.4:
SELECT
pets.id AS pets_id,
pets.name AS pets_name, pets.person_id AS pets_person_id,
persons_1.id AS persons_1_id, persons_1.firstname AS persons_1_firstname
FROM pets LEFT OUTER JOIN persons AS persons_1 ON
persons_1.id = pets.person_id ORDER BY persons_1.firstname
while under SA 2.0.15 I get this:
SELECT
pets.id AS pets_id,
pets.name AS pets_name, pets.person_id AS pets_person_id,
persons_1.id AS persons_1_id, persons_1.firstname AS persons_1_firstname
FROM pets LEFT OUTER JOIN persons AS persons_1 ON
persons_1.id = pets.person_id ORDER BY persons_2.firstname
that obviously fails, with the following error:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such column: persons_2.firstname
Putting a breakpoint just before applying that `.order_by()` and
inspecting the `col` returned by the function, I cannot spot any
difference in the object, under both SA I see
(Pdb) p col
Column('firstname', String(), table=<anon_1>)
Can you shed some light on what I can try to smooth this different
behaviour?
Thanks a lot in advance,
bye, lele.
[1]
https://gitlab.com/metapensiero/metapensiero.sqlalchemy.proxy
[2]
https://gitlab.com/metapensiero/metapensiero.sqlalchemy.proxy/-/blob/8db2c398aaf8a0bd679557f630c5c8433a1f4572/src/metapensiero/sqlalchemy/proxy/utils.py#L44-98
[3]
https://gitlab.com/metapensiero/metapensiero.sqlalchemy.proxy/-/blob/8db2c398aaf8a0bd679557f630c5c8433a1f4572/src/metapensiero/sqlalchemy/proxy/sorters.py#L156-210
--
nickname: Lele Gaifax | Dire che Emacs è "conveniente" è come
real: Emanuele Gaifas | etichettare l'ossigeno come "utile"
le...@etour.tn.it | -- Rens Troost