commit f897bea931f39cd42757b59ae054bfa3414cc84f
Author: Sofia Papagiannaki <papagian@gmail.com>
Date:   Wed Dec 21 16:16:32 2011 +0200

    sqlalchemy backend: fix metadata queries
    
    Refs:#1789

diff --git a/pithos/backends/lib/sqlalchemy/node.py b/pithos/backends/lib/sqlalchemy/node.py
index c763ffe..f3b5169 100644
--- a/pithos/backends/lib/sqlalchemy/node.py
+++ b/pithos/backends/lib/sqlalchemy/node.py
@@ -41,8 +41,7 @@ from sqlalchemy.engine.reflection import Inspector
 
 from dbworker import DBWorker
 
-from pithos.lib.filter import parse_filters
-
+from pithos.lib.filter import parse_filters, OPERATORS
 
 ROOTNODE  = 0
 
@@ -830,9 +829,6 @@ class Node(DBWorker):
         s = s.where(v.c.cluster != except_cluster)
         s = s.where(v.c.node.in_(select([self.nodes.c.node],
             self.nodes.c.parent == parent)))
-        if domain and filterq:
-            s = s.where(a.c.serial == v.c.serial)
-            s = s.where(a.c.domain == domain)
         
         s = s.where(n.c.node == v.c.node)
         s = s.where(and_(n.c.path > bindparam('start'), n.c.path < nextling))
@@ -843,22 +839,43 @@ class Node(DBWorker):
         if conj:
             s = s.where(or_(*conj))
         
-        if domain and filterq:
+        s = s.order_by(n.c.path)
+        
+        def filterout(r):
+            if not filterq:
+                return False
+            path, serial = r
             included, excluded, opers = parse_filters(filterq)
+            
+            #retrieve metadata
+            s = select([a.c.key, a.c.value])
+            s = s.where(a.c.domain == domain)
+            s = s.where(a.c.serial == serial)
+            rp = self.conn.execute(s)
+            meta = dict(rp.fetchall())
+            keyset= set([k.encode('utf8') for k in meta.keys()])
+            
             if included:
-                s = s.where(a.c.key.in_(x for x in included))
+                if not set(included) & keyset:
+                    return True
             if excluded:
-                s = s.where(not_(a.c.key.in_(x for x in excluded)))
-            if opers:
-                for k, o, v in opers:
-                    s = s.where(or_(a.c.key == k and a.c.value.op(o)(v)))
-        
-        s = s.order_by(n.c.path)
-        
+                if set(excluded) & keyset:
+                    return True
+            for k, op, v in opers:
+                k = k.decode('utf8')
+                v = v.decode('utf8')
+                if k not in meta:
+                    return True
+                operation = OPERATORS[op]
+                if not operation(meta[k], v):
+                    return True
+            return False
+    
         if not delimiter:
             s = s.limit(limit)
             rp = self.conn.execute(s, start=start)
-            r = rp.fetchall()
+            filter_ = lambda r : [t for t in r if not filterout(t)]
+            r = filter_(rp.fetchall())
             rp.close()
             return r, ()
         
@@ -875,6 +892,8 @@ class Node(DBWorker):
             props = rp.fetchone()
             if props is None:
                 break
+            if filterout(props):
+                continue
             path, serial = props
             idx = path.find(delimiter, pfz)
             
diff --git a/pithos/lib/filter.py b/pithos/lib/filter.py
index df935dd..6b9e1e3 100644
--- a/pithos/lib/filter.py
+++ b/pithos/lib/filter.py
@@ -32,10 +32,17 @@
 # or implied, of GRNET S.A.
 
 import re
+import operator
 
+_regexfilter = re.compile('(!?)\s*(\S+?)\s*(?:(=|!=|<=|>=|<|>)\s*(\S*?)\s*)?$', re.UNICODE)
 
-_regexfilter = re.compile('(!?)\s*(.+)\s*(=|!=|<=|>=|<|>)?\s*(.*)$', re.UNICODE)
-
+OPERATORS = {'=':operator.eq,
+             '!=':operator.ne,
+             '<=':operator.le,
+             '>=':operator.ge,
+             '<':operator.lt,
+             '>':operator.gt
+}
 
 def parse_filters(terms):
     included = []
@@ -49,9 +56,9 @@ def parse_filters(terms):
         neg, key, op, value = m.groups()
         if neg:
             excluded.append(key)
-        elif not value:
-            included.append(key)
         elif op:
             opers.append((key, op, value))
-
+        elif not value:
+            included.append(key)
+    
     return included, excluded, opers
diff --git a/pithos/tools/pithos-test b/pithos/tools/pithos-test
index 6c7fbcf..089378a 100755
--- a/pithos/tools/pithos-test
+++ b/pithos/tools/pithos-test
@@ -1684,9 +1684,6 @@ class ListSharing(BaseTestCase):
         self.assertTrue('o2' not in my_shared_objects)
     
 class TestGreek(BaseTestCase):
-    def tearDown(self):
-        pass
-    
     def test_create_container(self):
         self.client.create_container('φάκελος')
         self.assert_container_exists('φάκελος')
@@ -1796,7 +1793,7 @@ class TestGreek(BaseTestCase):
         
         meta = {'ποιότητα':'ΑΒ'}
         self.client.update_object_metadata('φάκελος', 'ο2', **meta)
-        objects = self.client.list_objects('φάκελος', meta='ποιότητα==ΑΑΑ')
+        objects = self.client.list_objects('φάκελος', meta='ποιότητα=ΑΑΑ')
         self.assertEquals(objects, ['ο1'])
         objects = self.client.list_objects('φάκελος', meta='ποιότητα!=ΑΑΑ')
         self.assertEquals(objects, ['ο2'])
@@ -1806,11 +1803,11 @@ class TestGreek(BaseTestCase):
         meta = {'έτος':'2012'}
         self.client.update_object_metadata('φάκελος', 'ο2', **meta)
         objects = self.client.list_objects('φάκελος', meta='έτος<2012')
-        self.assertEquals(objects, ['ο1'])
+        self.assertEquals(objects, ['ο3'])
         objects = self.client.list_objects('φάκελος', meta='έτος<=2012')
-        self.assertEquals(objects, ['ο1', 'ο2'])
-        objects = self.client.list_objects('φάκελος', meta='έτος<2012,έτος!=2012')
-        self.assertEquals(objects, ['ο2'])
+        self.assertEquals(objects, ['ο2', 'ο3'])
+        objects = self.client.list_objects('φάκελος', meta='έτος<2012,έτος!=2011')
+        self.assertEquals(objects, '')
     
     def test_groups(self):
         #create a group
