selectors.py
changeset 6366 1806148d6ce8
parent 6141 b8287e54b528
parent 6364 ad9ed9803eb6
child 6389 72ba82a26e05
--- a/selectors.py	Thu Sep 23 23:28:58 2010 +0200
+++ b/selectors.py	Wed Sep 29 16:16:32 2010 +0200
@@ -194,6 +194,7 @@
 
 import logging
 from warnings import warn
+from operator import eq
 
 from logilab.common.deprecation import class_renamed
 from logilab.common.compat import all, any
@@ -530,17 +531,26 @@
 
 
 class multi_lines_rset(Selector):
-    """If `nb` is specified, return 1 if the result set has exactly `nb` row of
-    result. Else (`nb` is None), return 1 if the result set contains *at least*
+    """Return 1 if the operator expression matches between `num` elements
+    in the result set and the `expected` value if defined.
+    
+    By default, multi_lines_rset(expected) matches equality expression:
+        `nb` row(s) in result set equals to expected value
+    But, you can perform richer comparisons by overriding default operator:
+        multi_lines_rset(expected, operator.gt)
+    
+    If `expected` is None, return 1 if the result set contains *at least*
     two rows.
+    If rset is None, return 0.
     """
-    def __init__(self, nb=None):
-        self.expected = nb
+    def __init__(self, expected=None, operator=eq):
+        self.expected = expected
+        self.operator = operator
 
     def match_expected(self, num):
         if self.expected is None:
             return num > 1
-        return num == self.expected
+        return self.operator(num, self.expected)
 
     @lltrace
     def __call__(self, cls, req, rset=None, **kwargs):
@@ -1039,12 +1049,12 @@
             return self.score_entity(kwargs['entity'])
         if rset is None:
             return 0
-        user = req.user
-        action = self.action
         if row is None:
             score = 0
             need_local_check = []
             geteschema = req.vreg.schema.eschema
+            user = req.user
+            action = self.action
             for etype in rset.column_types(0):
                 if etype in BASE_TYPES:
                     return 0
@@ -1061,9 +1071,11 @@
             if need_local_check:
                 # check local role for entities of necessary types
                 for i, row in enumerate(rset):
-                    if not rset.description[i][0] in need_local_check:
+                    if not rset.description[i][col] in need_local_check:
                         continue
-                    if not self.score(req, rset, i, col):
+                    # micro-optimisation instead of calling self.score(req,
+                    # rset, i, col): rset may be large
+                    if not rset.get_entity(i, col).cw_has_perm(action):
                         return 0
                 score += 1
             return score