gorilla-co / odata-query

An OData v4 query parser and transpiler for Python

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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! 😅