gorilla-co / odata-query

An OData v4 query parser and transpiler for Python

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Does the parser support `contains(field, value)` comparisons?

al-the-x opened this issue · comments

Hello! Thank you for this wonderful contribution to the community! We have been using odata-query with our Django / DRF project to provide OData representations of our 1st-party objects in Salesforce via External Objects, but as we are expanding the usage of OData, we have encountered some difficulty with the parser. For example, when exposing one of our Django models via a filterable OData API for Salesforce, we encountered this error:

TypeException

Cannot apply 'Eq' to 'Call(func=Identifier(name='contains'), args=[Identifier(name='category'), String(val='danielle hutchens')])'

From odata_query/django/django_q.py in visit_Compare at line 194:

node: Compare(comparator=Eq(), left=Call(func=Identifier(name='contains'), args=[Identifier(name='category'), String(val='danielle hutchens')]), right=Boolean(val='true'))
. . .

From odata_query/django/shorthand.py in apply_odata_query at line 24:

odata_query:

"contains(category,'danielle hutchens') eq true or contains(email,'danielle hutchens') eq true or contains(filename,'danielle hutchens') eq true or contains(file_id,'danielle hutchens') eq true or contains(path,'danielle hutchens') eq true or contains(revision,'danielle hutchens') eq true or contains(content_hash,'danielle hutchens') eq true or contains(subcategory,'danielle hutchens') eq true or contains(hyker__sfaccountid,'danielle hutchens') eq true or contains(hyker__sfopportunityid,'danielle hutchen...

Can you confirm whether odata-query supports these kinds of comparisons? Are we (or Salesforce External Objects) doing something wrong?

Hey, glad you like the library, thanks!

It seems that this is a bug, specifically when using the Django backend. I've tested against both our SQLAlchemy app and Django app, and the Django test does indeed fail. Good catch!

In the case of contains however, the comparison isn't strictly necessary as contains already returns a boolean. So your example should work if you just use contains(category,'danielle hutchens') or contains(email,'danielle hutchens') or ... (without the eq true).

I'm gonna look into this, as your query is also correct and should just work.

Hmmm, I though I'd found a solution in db85807. Turns out it relies on new functionality only introduced in Django 4. I'll have to rethink my fix!

Happy to contribute here. For our use case, Salesforce is the client, so we don't really have control of the query that is constructed. I suppose we could inspect the AST and drop the Eq with a left-hand Call for the Call itself, if that's the issue?

Hey @al-the-x ,
sorry to keep you waiting for so long. I felt like I was perpetually within 5 minutes of fixing this, but things kept popping up.
#20 would fix this issue, but includes quite a big change to how Django queries are constructed (in line with new Django 4 features). I wouldn't recommend updating production software blindly, as some issues are present relating to upstream Django issues (e.g. https://code.djangoproject.com/ticket/33705).

Your fix would definitely be a good band-aid if updating is not an option!