[CalendarServer-changes] [1195] CalendarServer/branches/users/cdaboo/sqlprops-1126/twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Fri Feb 16 11:00:45 PST 2007


Revision: 1195
          http://trac.macosforge.org/projects/calendarserver/changeset/1195
Author:   cdaboo at apple.com
Date:     2007-02-16 11:00:45 -0800 (Fri, 16 Feb 2007)

Log Message:
-----------
Add methods for "batch" queries on multiple properties and across multiple resources.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/sqlprops-1126/twistedcaldav/sqlprops.py
    CalendarServer/branches/users/cdaboo/sqlprops-1126/twistedcaldav/test/test_sqlprops.py

Modified: CalendarServer/branches/users/cdaboo/sqlprops-1126/twistedcaldav/sqlprops.py
===================================================================
--- CalendarServer/branches/users/cdaboo/sqlprops-1126/twistedcaldav/sqlprops.py	2007-02-15 19:33:00 UTC (rev 1194)
+++ CalendarServer/branches/users/cdaboo/sqlprops-1126/twistedcaldav/sqlprops.py	2007-02-16 19:00:45 UTC (rev 1195)
@@ -44,15 +44,13 @@
 
 class sqlPropertyStore (object):
     """
-
+    A dead property store that uses an SQLite database backend.
     """
  
     def _encode(clazz, name):
-        return urllib.quote("{%s}%s" % name, safe='{}:')
+        return "{%s}%s" % name
 
     def _decode(clazz, name):
-        name = urllib.unquote(name)
-
         index = name.find("}")
     
         if (index is -1 or not len(name) > index or not name[0] == "{"):
@@ -99,6 +97,58 @@
 
         return doc.root_element
 
+    def getAll(self, qnames):
+        """
+        Read properties from index.
+        
+        @param qnames: C{list} of C{tuple} of property namespace and name.
+        @return: a C{list} of property classes
+        """
+        if not qnames:
+            return None
+
+        if not self.index:
+            raise HTTPError(StatusResponse(
+                responsecode.NOT_FOUND,
+                "No such property: {%s}%s" % qnames[0]
+            ))
+            
+        values = self.index.getAllPropertyValues(self.rname, map(self._encode, qnames))
+        
+        results = []
+        for value in values.itervalues():
+            doc = davxml.WebDAVDocument.fromString(value)
+            results.append(doc.root_element)
+        return results
+
+    def getAllResources(self, qnames):
+        """
+        Read properties for all child resources from index.
+        
+        @param qnames: C{list} of C{tuple} of property namespace and name.
+        @return: a C{dict} with resource name as keys and C{list} of property classes as values
+        """
+        if not qnames:
+            return None
+
+        if not self.index:
+            raise HTTPError(StatusResponse(
+                responsecode.NOT_FOUND,
+                "No such property: {%s}%s" % qnames[0]
+            ))
+            
+        values = self.index.getAllResourcePropertyValues(map(self._encode, qnames))
+        results = {}
+        
+        for key, value in values.iteritems():
+            pvalues = []
+            for pvalue in value.itervalues():
+                doc = davxml.WebDAVDocument.fromString(pvalue)
+                pvalues.append(doc.root_element)
+            results[key] = pvalues
+        
+        return results
+
     def set(self, property):
         """
         Write property into index.
@@ -150,8 +200,7 @@
 
         if self.index:
             results = self.index.listProperties(self.rname)
-            result = [self._decode(name) for name in results]
-            return result
+            return map(self._decode, results)
         else:
             return []
 
@@ -210,8 +259,57 @@
             return members[0]
         else:
             raise ValueError("Multiple properties of the same name %s stored for resource %s" % (pname, rname,))
+
+    def getAllPropertyValues(self, rname, pnames):
+        """
+        Get specified property values from specific resource.
+    
+        @param rname: a C{str} containing the resource name.
+        @param pnames: a C{list} of C{str} containing the name of the properties to get.
+        @return: a C{dict} containing property name/value.
+        """
         
+        # Remove what is there, then add it back.
+        log.msg("getAllPropertyValues: %s \"%s\"" % (self.dbpath, pnames))
+        properties = {}
+        statement = "select PROPERTYNAME, PROPERTYVALUE from PROPERTIES where RESOURCENAME = :1 and ("
+        args = [rname]
+        for i, pname in enumerate(pnames):
+            if i != 0:
+                statement += " or "
+            statement += "PROPERTYNAME=:%s" % (i + 2,)
+            args.append(pname)
+        statement += ")"
 
+        for row in self._db_execute(statement, *args):
+            properties[row[0]] = row[1]
+
+        return properties
+
+    def getAllResourcePropertyValues(self, pnames):
+        """
+        Get specified property values from all resources.
+    
+        @param pnames: a C{list} of C{str} containing the name of the properties to get.
+        @return: a C{dict} containing C{str} keys (names of child resources) and C{dict} values of property name/value.
+        """
+        
+        # Remove what is there, then add it back.
+        log.msg("getAllPropertyValues: %s \"%s\"" % (self.dbpath, pnames))
+        members = {}
+        statement = "select RESOURCENAME, PROPERTYNAME, PROPERTYVALUE from PROPERTIES where "
+        args = []
+        for i, pname in enumerate(pnames):
+            if i != 0:
+                statement += " or "
+            statement += "PROPERTYNAME=:%s" % (i + 1,)
+            args.append(pname)
+
+        for row in self._db_execute(statement, *args):
+            members.setdefault(row[0], {})[row[1]] = row[2]
+
+        return members
+
     def removeProperty(self, rname, pname):
         """
         Remove a property.

Modified: CalendarServer/branches/users/cdaboo/sqlprops-1126/twistedcaldav/test/test_sqlprops.py
===================================================================
--- CalendarServer/branches/users/cdaboo/sqlprops-1126/twistedcaldav/test/test_sqlprops.py	2007-02-15 19:33:00 UTC (rev 1194)
+++ CalendarServer/branches/users/cdaboo/sqlprops-1126/twistedcaldav/test/test_sqlprops.py	2007-02-16 19:00:45 UTC (rev 1195)
@@ -15,6 +15,8 @@
 #
 # DRI: Wilfredo Sanchez, wsanchez at apple.com
 ##
+import time
+from twistedcaldav.root import RootResource
 from twistedcaldav import customxml
 from twistedcaldav import caldavxml
 from twisted.web2.dav import davxml
@@ -68,12 +70,49 @@
                         msg="Could not find property %s." % prop)
         self.assertTrue(index.get(prop.qname()) == prop,
                         msg="Could not get property %s." % prop)
-        
+    
+    def _testPropertyList(self, proplist):
+        self.assertTrue(len(proplist) == len(SQLProps.props),
+                        msg="Number of properties returned %s not equal to number queried %s." % (len(proplist), len(SQLProps.props),))
+        for prop in SQLProps.props:
+            for p in proplist:
+                if prop == p:
+                    proplist.remove(p)
+                    break
+        self.assertTrue(len(proplist) == 0,
+                        msg="Incorrect properties returned %s." % proplist)
+
+    def _testResourcePropertyList(self, num_resources, resourcedict):
+        self.assertTrue(len(resourcedict) == num_resources,
+                        msg="Number of resources returned %s not equal to number queried %s." % (len(resourcedict), num_resources,))
+        for i in xrange(num_resources):
+            fname = "file%04s.ics" % (i,)
+            self.assertTrue(resourcedict.has_key(fname),
+                            msg="Resource %s not returned in query results" % (fname,))
+            self._testPropertyList(resourcedict[fname])
+
+    def _setupMultipleResources(self, number):
+        self.collection_name, self.collection_uri = self.mkdtemp("sql")
+        for i in xrange(number):
+            rsrc = CalDAVFile(os.path.join(self.collection_name, "file%04s.ics" % (i,)))
+            index = sqlPropertyStore(rsrc)
+            for prop in SQLProps.props:
+                index.set(prop)
+        return index
+
     def test_db_init_directory(self):
         self.collection_name, self.collection_uri = self.mkdtemp("sql")
         rsrc = CalDAVFile(self.collection_name)
         index = sqlPropertyStore(rsrc)
         db = index.index._db()
+        self.assertTrue(os.path.exists(os.path.join(os.path.dirname(self.collection_name), SQLPropertiesDatabase.dbFilename)),
+                        msg="Could not initialize index via collection resource.")
+
+    def test_db_init_root(self):
+        self.collection_name, self.collection_uri = self.mkdtemp("sql")
+        rsrc = RootResource(self.collection_name)
+        index = sqlPropertyStore(rsrc)
+        db = index.index._db()
         self.assertTrue(os.path.exists(os.path.join(self.collection_name, SQLPropertiesDatabase.dbFilename)),
                         msg="Could not initialize index via collection resource.")
 
@@ -121,3 +160,28 @@
         for prop in SQLProps.props:
             self.assertFalse(index.contains(prop.qname()),
                             msg="Could not find property %s." % prop)
+
+    def test_getallproperties(self):
+        index = self._setUpIndex()
+        for prop in SQLProps.props:
+            self._setProperty(index, prop)
+        
+        result = index.getAll([p.qname() for p in SQLProps.props])
+        self._testPropertyList(result)
+
+    def test_getallresourceproperties(self):
+        num_resources = 10
+        index = self._setupMultipleResources(num_resources)
+        result = index.getAllResources([p.qname() for p in SQLProps.props])
+        self._testResourcePropertyList(num_resources, result)
+
+#    def test_timegetallresourceproperties(self):
+#        num_resources = 1000
+#        index = self._setupMultipleResources(num_resources)
+#        t1 = time.time()
+#        result = index.getAllResources([p.qname() for p in SQLProps.props])
+#        t2 = time.time()
+#        self.assertTrue(t1 == t2,
+#                        msg="Time for 1000 prop query = %s" % (t2 - t1,))
+#
+#        self._testResourcePropertyList(num_resources, result)

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070216/45660d33/attachment.html


More information about the calendarserver-changes mailing list