I think I am wrong about the API being a limiting factor here: with smarter code, we could pretty easily avoid the recursion problems by changing Store._set_expr() to something like this:
...
left_select = self._get_select()
right_select = other._get_select()
# Try to flatten nested set expressions.
if (isinstance(left_select, expr_cls) and left_select.all == all and left_select.limit is Undef and left_select.offset is Undef):
subexprs = left_select.exprs + (right_select,)
else:
subexprs = (left_select, right_select)
expr = expr_cls(*subexprs, all=all)
...
The idea being to take advantage of left associativity of set operations to generate a shallower expression tree. It looks like this would bring the same benefit to the SQLObject compatibility layer with no changes.
I think I am wrong about the API being a limiting factor here: with smarter code, we could pretty easily avoid the recursion problems by changing Store._set_expr() to something like this:
... left_select, expr_cls) and left_select.all == all and
left_select. limit is Undef and left_select.offset is Undef):
left_select = self._get_select()
right_select = other._get_select()
# Try to flatten nested set expressions.
if (isinstance(
subexprs = left_select.exprs + (right_select,)
else:
subexprs = (left_select, right_select)
expr = expr_cls(*subexprs, all=all)
...
The idea being to take advantage of left associativity of set operations to generate a shallower expression tree. It looks like this would bring the same benefit to the SQLObject compatibility layer with no changes.