[Zope-CVS] CVS: Packages/pypes/pypes - interfaces.py:1.26 query.py:1.19

Casey Duncan casey at zope.com
Thu Jun 10 00:44:55 EDT 2004


Update of /cvs-repository/Packages/pypes/pypes
In directory cvs.zope.org:/tmp/cvs-serv7303

Modified Files:
	interfaces.py query.py 
Log Message:
Define and implement resultSet() method for IPartialResult classes


=== Packages/pypes/pypes/interfaces.py 1.25 => 1.26 ===
--- Packages/pypes/pypes/interfaces.py:1.25	Wed Jun  9 00:23:12 2004
+++ Packages/pypes/pypes/interfaces.py	Thu Jun 10 00:44:24 2004
@@ -742,12 +742,13 @@
         is provided that does not match an input name, raise PypesQueryError.
         """
         
-    #def resultSet(*names):
-    #    """Return an ISet object containing the items from the inputs named.
-    #    If a single name is specified, then return a set of matching objects
-    #    from the input. If multiple names are specified, return a set of
-    #   tuples of the matching items from the cooresponding named inputs.
-    #    """
+    def resultSet(name):
+        """Return an ISet object containing the items from the input named
+        that are matched by the criteria. If the input is not filtered by the
+        criteria, then it may be returned.
+        
+        If name does not coorespond to an input, raise PypesQueryError.
+        """
 
 class IQueryResult(Interface):
     """Result from running a query"""


=== Packages/pypes/pypes/query.py 1.18 => 1.19 ===
--- Packages/pypes/pypes/query.py:1.18	Wed Jun  9 22:38:38 2004
+++ Packages/pypes/pypes/query.py	Thu Jun 10 00:44:24 2004
@@ -46,6 +46,9 @@
 from zope.interface import implements
 from compiler import ast
 from BTrees.OOBTree import OOBTree, OOTreeSet
+from BTrees.IIBTree import IITreeSet
+from pypes import services
+from pypes.identity import IdentitySet
 from pypes.interfaces import IPartialResult, IExtent
 from pypes.exceptions import PypesLookupError, PypesQueryInputError, CantProcess
 from pypes.exceptions import PypesQueryError
@@ -99,8 +102,78 @@
                 inmap[name] = set1
         return inmap                    
 
+class PartialResult:
+    """Abstract partial result class"""
+    
+    _inputs = None # Input map
+    _criteria = None # Criteria expression
+    
+    def inputMap(self):
+        return self._inputs.copy()
+        
+    def criteriaExpr(self):
+        return self._criteria
+    
+    def namesUsed(self):
+        return self._criteria.freeNames(self._inputs.keys())
+    
+    def union(self, other):
+        raise NotImplementedError
+    
+    def intersection(self, other):
+        raise NotImplementedError
+    
+    def iterResult(self, *names, **fixed):
+        raise NotImplementedError
+        
+    def resultSet(self, name):
+        """Return a set of objects from the input named which satisfy the
+        criteria.
+        """
+        if name not in self._inputs:
+            raise PypesQueryError('no input named "%s"' % name)
+        if self._criteria is None:
+            return self._inputs[name]
+        if name in self._criteria.freeNames(self._inputs.keys()):
+            # Input is referenced in criteria, create set from product result
+            maxlength = len(self._inputs[name])
+            length = 0
+            idset = IITreeSet()
+            insert = idset.insert
+            for obj in self.iterResult(name):
+                try:
+                    pypesid = obj._pypes_id_
+                except AttributeError:
+                    # object not identified
+                    idset = None
+                    break
+                else:
+                    if insert(pypesid):
+                        length += 1
+                    elif length == maxlen:
+                        # All objects from the input were found
+                        return self._inputs[name]
+            if idset is not None:
+                dbconn = services.accesspointFrom(self._inputs[name])
+                return IdentitySet.fromIdSet(
+                    idset, dbconn=dbconn, length=length)
+            else:
+                # can't use identity set
+                # XXX won't work with unhashable objects
+                return Set(self.iterResult(name))
+        else:
+            # Input not referenced from criteria, if any results are
+            # generated, then we can return the entire input set. If
+            # not return an empty set.
+            try:
+                self.iterResult(name).next()
+            except StopIteration:
+                return IdentitySet()
+            else:
+                return self._inputs[name]
 
-class CartProduct:
+
+class CartProduct(PartialResult):
     """Cartesian product of one or more inputs to a query. Allows lazy 
     evaluation, and efficient combinatorial operations
     """
@@ -119,12 +192,6 @@
         self._inputs = input_map
         self._criteria = criteria
     
-    def inputMap(self):
-        return self._inputs.copy()
-        
-    def criteriaExpr(self):
-        return self._criteria
-    
     def namesUsed(self):
         if self._criteria is not None:
             return self._criteria.freeNames(self._inputs.keys())
@@ -218,11 +285,7 @@
                 if i > 0:
                     i = 0
                     break
-    
-    def resultSet(self, *names):
-        """Return a unique set of results from the named inputs where the
-        criteria is satisfied
-        """
+
 
 def equijoin(left_iter, left_expr, right_iter, right_expr):
     """Join the values of the left_iter and right_iter iterables where the
@@ -248,7 +311,7 @@
             if isinstance(left_by_val, dict):
                 # Likely val is not hashable
                 # switch to using BTree which does not require hashable keys
-                # (but insertion is slower)
+                # (but lookup is slower)
                 left_by_val = OOBTree(left_by_val)
                 left_by_val[val] = left_by_val.get(val, []) + [obj]
             else:
@@ -287,7 +350,7 @@
                 if isinstance(right_by_val, dict):
                     # Likely val is not hashable switch to using a
                     # BTree which does not require hashable keys
-                    # (but insertion is slower)
+                    # (but lookup is slower)
                     right_by_val = OOBTree(right_by_val)
                     right_by_val[val] = right_by_val.get(val, []) + [obj]
                 else:
@@ -328,7 +391,7 @@
                 for left in left_matches:
                     yield left, right
 
-class Join:
+class Join(PartialResult):
     """Join of multiple inputs using a criteria expression.
     
     This implementation handles joins of two inputs each on a separate side
@@ -391,15 +454,6 @@
         self._left_func = left_expr.makeFunction(left_names)
         self._right_name, = right_names
         self._right_func = right_expr.makeFunction(right_names)
-    
-    def inputMap(self):
-        return self._inputs.copy()
-        
-    def criteriaExpr(self):
-        return self._criteria
-    
-    def namesUsed(self):
-        return self._criteria.freeNames(self._inputs.keys())
         
     def union(self, other):
         inputs = union_input_maps(self.inputMap(), other.inputMap())
@@ -488,7 +542,7 @@
             return self._iterJoinOtherProduct(names, joined_names)
 
 
-class ActualizedResult:
+class ActualizedResult(PartialResult):
     """Partial result with greedy evaluation.
     
     When instantiated, the inputs are processed immediately against the
@@ -540,21 +594,18 @@
             self._inputs = {}
             for name, ipt in input_map.items():
                 if name in filters:
-                    self._inputs[name] = Set(
+                    self._inputs[name] = ipt = Set(
                         ifilter(filters[name].makeFunction(name), ipt))
                 else:
                     self._inputs[name] = ipt
+                if not ipt:
+                    # If one of the inputs is empty, they all are
+                    empty = IdentitySet()
+                    for name in input_map:
+                        self._inputs[name] = empty
+                    break
         else:
             self._inputs = input_map.copy()
-    
-    def inputMap(self):
-        return self._inputs.copy()
-        
-    def criteriaExpr(self):
-        return self._criteria
-    
-    def namesUsed(self):
-        return self._criteria.freeNames(self._inputs.keys())
         
     def union(self, other):
         """A union with an actualized result returns a new partial result
@@ -594,6 +645,11 @@
                 else:
                     return _empty_iter
         return CartProduct(self._inputs).iterResult(*names, **fixed)
+    
+    def resultSet(self, name):
+        if name not in self._inputs:
+            raise PypesQueryError('no input named "%s"' % name)
+        return self._inputs[name]
 
 
 def sort(iterable, expression, order=ascending, limit=None):




More information about the Zope-CVS mailing list