diff --git a/djaosdb/sql2mongo/operators.py b/djaosdb/sql2mongo/operators.py index 05a0340580145208f91fee9772c82f675b7f50a4..12e53e6f6cdf442497898abccd681cb76a54d24c 100644 --- a/djaosdb/sql2mongo/operators.py +++ b/djaosdb/sql2mongo/operators.py @@ -59,9 +59,6 @@ class _UnaryOp(_Op): super().__init__(*args, **kwargs) self._op = None - def negate(self): - raise NotImplementedError - def evaluate(self): self.rhs.evaluate() @@ -79,12 +76,6 @@ class _BinaryOp(_Op): def _field(self): return self._identifier.field - def negate(self): - raise SQLDecodeError('Negating IN/NOT IN not supported') - - def to_mongo(self): - raise NotImplementedError - def evaluate(self): pass @@ -107,12 +98,6 @@ class _InNotInOp(_BinaryOp): else: self._in.append(None) - def negate(self): - raise SQLDecodeError('Negating IN/NOT IN not supported') - - def to_mongo(self): - raise NotImplementedError - def _to_caosdb(self, op, nested_select): if op=="$in" and nested_select.left_table == self._field: pipeline = nested_select._make_pipeline() @@ -176,6 +161,9 @@ class LikeOp(_BinaryOp): self._regex = None self._make_regex(self.statement.next()) + def negate(self): + self.is_negated = True + def _make_regex(self, token): index = SQLToken.placeholder_index(token) @@ -191,7 +179,7 @@ class LikeOp(_BinaryOp): def to_mongo(self): return {"type": "pov", "p": self._field, "o": " LIKE ", "v": self._regex, - "negation": False} + "negation": self.is_negated} class IsOp(_BinaryOp): @@ -231,6 +219,7 @@ class IsOp(_BinaryOp): return result + class BetweenOp(_BinaryOp): def __init__(self, *args, **kwargs): @@ -612,7 +601,7 @@ class CmpOp(_Op): "v": self._constant} if self._operator: - resule["o"] = self._operator + result["o"] = self._operator if ref: result["ref"] = ref diff --git a/tests/test_new.py b/tests/test_new.py index 3310a0b7664bdd7b9ee03e7eb2d9f0f814d4faf6..360fe074fe62739488794b00daf0dd95d12381f6 100644 --- a/tests/test_new.py +++ b/tests/test_new.py @@ -886,3 +886,59 @@ def test_query(): "v": "v4", }], }]} + +def test_not_in(): + sql = """ + SELECT COUNT(*) AS "__count" + FROM "A" WHERE ( + "A"."State" = %(0)s + AND NOT ( "A"."p1" iLIKE %(1)s) + AND NOT ("A"."p2" iLIKE %(2)s) + AND ("A"."p1" iLIKE %(3)s + OR "A"."p2" iLIKE %(4)s + )""" + params = ('published', '%term1%', '%term2%', '%term3%', '%term4%') + cached_record_types = [ + "A", + ] + connection = _MockConnection(cached_record_types=cached_record_types) + q = Query(connection=connection, sql=sql, params=params) + caosdb_params = q._query._to_caosdb()[2] + assert caosdb_params["count"] == "__count" + assert caosdb_params["filter"] == { + 'type': 'and', + 'elements': [{ + 'negation': False, + 'o': '=', + 'p': 'State', + 'type': 'pov', + 'v': 'published', + }, { + 'negation': True, + 'o': ' LIKE ', + 'p': 'p1', + 'type': 'pov', + 'v': '*term1*', + }, { + 'negation': True, + 'o': ' LIKE ', + 'p': 'p2', + 'type': 'pov', + 'v': '*term2*', + }, { + 'type': 'or', + 'elements': [{ + 'negation': False, + 'o': ' LIKE ', + 'p': 'p1', + 'type': 'pov', + 'v': '*term3*', + }, { + 'negation': False, + 'o': ' LIKE ', + 'p': 'p2', + 'type': 'pov', + 'v': '*term4*', + }], + }], + }