awslabs / awslabs/aws-appflow-custom-connector-python

OR conditions not parenthesized in filter expression → malformed SOQL

Open
#46 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
51
Forks
33
PR merge metrics
No merged PRs in 30d

Description

Report: OR expressions are not correctly parsed into parenthesized SOQL

Describe the issue

When using this sample connector (SalesforceExampleConnector), a filter expression with multiple OR conditions generates a malformed SOQL query without parentheses. This results in a Salesforce error when executing the query via AppFlow.

To Reproduce

Given the following filter expression:

`FieldA = "false" AND FieldB = "03" AND (FieldC = "01" OR FieldC = "02" OR FieldC = "04")
`
The resulting SOQL becomes:

`WHERE FieldA = false AND FieldB = '03' AND FieldC = '01' OR FieldC = '02' OR FieldC = '04'
`
As you can see, the OR expressions are not enclosed in parentheses, leading to:

MALFORMED_QUERY: unexpected token: 'OR'

Expected behavior

The OR clause should be grouped inside parentheses to preserve logical precedence:

```
... AND (
FieldC = '01' OR
FieldC = '02' OR
FieldC = '04'
)
```

Workaround

As a temporary workaround, we modified translate_filter_expression in builder.py to detect the specific field combination and return a hardcoded string:

```
if ("FieldA" in filter_expression and
"FieldB" in filter_expression and
"FieldC" in filter_expression):
return "FieldA = false AND FieldB = '03' AND (...)", ""
```

However, this is not scalable.

Root Cause Suspected

It seems the visitOrBinary method in the visitor class does not parenthesize the left/right sides of the expression during recursive traversal. This breaks correct query formation in nested OR/AND combinations.

Suggested Fix

In SalesforceQueryFilterExpressionVisitor, the visitOrBinary function should explicitly add parentheses:

```
def visitOrBinary(self, ctx):
is_outermost = not self.inside_or_expression
if is_outermost:
self.inside_or_expression = True
self.query_builder.write('(')

self.visit(ctx.getChild(0))
self.query_builder.write(' or ')
self.visit(ctx.getChild(2))

if is_outermost:
self.query_builder.write(') ')
self.inside_or_expression = False

return self.query_builder.getvalue()
```

Additional context

Happy to contribute a PR if needed. Please advise on preferred implementation.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.