From 34d3ff3c8787de1bb877548c00eec2136e7ed0fb Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Sun, 1 Nov 2020 21:20:32 +0100
Subject: [PATCH] handling for negating like clauses

---
 djaosdb/sql2mongo/operators.py | 23 ++++----------
 tests/test_new.py              | 56 ++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 17 deletions(-)

diff --git a/djaosdb/sql2mongo/operators.py b/djaosdb/sql2mongo/operators.py
index 05a0340..12e53e6 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 3310a0b..360fe07 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*',
+            }],
+        }],
+    }
-- 
GitLab