Implicit Support for SQLAlchemy's Query-API has been removed
tstadel opened this issue · comments
Problem Description:
Till 0.6.0 (inclusive) we could pass a sqlalchemy.orm.Query
object to odata_query.sqlalchemy.apply_odata_query
and it worked. With 0.7.0 this changed and apply_odata_query
breaks with the following exception:
AttributeError: 'Query' object has no attribute 'columns_clause_froms'
Example code to reproduce:
from odata_query.sqlalchemy import apply_odata_query
orm_query = session.query(MyModel) # This is a SQLAlchemy Query object
odata_query = "name eq 'test'" # This will usually come from a query string parameter.
query = apply_odata_query(orm_query, odata_query) # this breaks
results = query.all()
Notes:
The title deliberately contains the word "implicit" as apply_odata_query
's query
param has type hint sqlalchemy.sql.expression.ClauseElement
and sqlalchemy.orm.Query
does not inherit from it.
So this issue could also be seen as the question whether it is intended to support SQLAlchemy's Query-API in general as it is kind of deprecated but I guess a lot of folks out there are still using it.
This was definitely not intended, so thanks for reporting this and for the simple reproducing code!
I think it'd be relatively easy to add a test on this behavior, fix the regression, and add it to the documentation/type hint while we're at it. I'll have a look soon!
I just released 0.7.1 which should fix this. Feel free to try it out!
I just released 0.7.1 which should fix this. Feel free to try it out!
@OliverHofkens I tried it out, but unfortunately if I run the example code from above I get the following error when running query.all()
:
AttributeError: 'Select' object has no attribute 'all'
I guess that's due to returning a Select
and not as previously a Query
object.
I guess something like
clause_element: ClauseElement = query
if isinstance(query, Query):
# For now, we keep supporting the 1.x style of queries unofficially.
# GITHUB-34
clause_element = query.__clause_element__()
model = clause_element.columns_clause_froms[0].entity_namespace
should resolve this. But I'm not an expert on SQLAlchemy internals.
My bad, the test case was incomplete. Hopefully 0.7.2
fixes it for real! 😅