[CalendarServer-changes] [10617] CalendarServer/trunk/twext/who
source_changes at macosforge.org
source_changes at macosforge.org
Fri Feb 1 09:46:16 PST 2013
Revision: 10617
http://trac.calendarserver.org//changeset/10617
Author: wsanchez at apple.com
Date: 2013-02-01 09:46:16 -0800 (Fri, 01 Feb 2013)
Log Message:
-----------
Add recordWith*() conveniance methods, implement in XML.
Modified Paths:
--------------
CalendarServer/trunk/twext/who/directory.py
CalendarServer/trunk/twext/who/idirectory.py
CalendarServer/trunk/twext/who/test/test_directory.py
CalendarServer/trunk/twext/who/test/test_xml.py
CalendarServer/trunk/twext/who/xml.py
Modified: CalendarServer/trunk/twext/who/directory.py
===================================================================
--- CalendarServer/trunk/twext/who/directory.py 2013-02-01 16:30:18 UTC (rev 10616)
+++ CalendarServer/trunk/twext/who/directory.py 2013-02-01 17:46:16 UTC (rev 10617)
@@ -27,9 +27,11 @@
from twisted.python.util import FancyEqMixin
+from twext.who.idirectory import DirectoryServiceError
from twext.who.idirectory import QueryNotSupportedError
from twext.who.idirectory import FieldName, RecordType
from twext.who.idirectory import Operand
+from twext.who.idirectory import DirectoryQueryMatchExpression
from twext.who.idirectory import IDirectoryService, IDirectoryRecord
@@ -65,29 +67,55 @@
def recordsFromQuery(self, expressions, operand=Operand.AND):
- results = None
+ expressionIterator = iter(expressions)
+ try:
+ expression = expressionIterator.next()
+ except StopIteration:
+ return set()
+
+ results = self.recordsFromExpression(expression)
+
for expression in expressions:
+ if (operand == Operand.AND and not results):
+ # No need to bother continuing here
+ return set()
+
recordsMatchingExpression = self.recordsFromExpression(expression)
- if results is None:
- results = recordsMatchingExpression
- break
-
if operand == Operand.AND:
- raise NotImplementedError()
+ results &= recordsMatchingExpression
elif operand == Operand.OR:
- raise NotImplementedError()
+ results |= recordsMatchingExpression
else:
raise QueryNotSupportedError("Unknown operand: %s" % (operand,))
- if results is None:
- return ()
-
return results
+ def recordsWithFieldValue(self, fieldName, value):
+ return self.recordsFromExpression(DirectoryQueryMatchExpression(fieldName, value))
+ def recordWithUID(self, uid):
+ return uniqueResult(self.recordsWithFieldValue(FieldName.uid, uid))
+
+ def recordWithGUID(self, guid):
+ return uniqueResult(self.recordsWithFieldValue(FieldName.guid, guid))
+
+ def recordsWithRecordType(self, recordType):
+ return self.recordsWithFieldValue(FieldName.recordType, recordType)
+
+ def recordWithShortName(self, recordType, shortName):
+ return uniqueResult(self.recordsFromQuery((
+ DirectoryQueryMatchExpression(FieldName.recordType, recordType),
+ DirectoryQueryMatchExpression(FieldName.shortNames, shortName ),
+ )))
+
+ def recordsWithEmailAddress(self, emailAddress):
+ return self.recordsWithFieldValue(FieldName.emailAddresses, emailAddress)
+
+
+
class DirectoryRecord(FancyEqMixin, object):
implements(IDirectoryRecord)
@@ -150,3 +178,14 @@
return self.fields[fieldName]
except KeyError:
raise AttributeError(name)
+
+
+
+def uniqueResult(values):
+ result = None
+ for value in values:
+ if result is None:
+ result = value
+ else:
+ raise DirectoryServiceError("Multiple values found where one expected.")
+ return result
Modified: CalendarServer/trunk/twext/who/idirectory.py
===================================================================
--- CalendarServer/trunk/twext/who/idirectory.py 2013-02-01 16:30:18 UTC (rev 10616)
+++ CalendarServer/trunk/twext/who/idirectory.py 2013-02-01 17:46:16 UTC (rev 10617)
@@ -167,13 +167,57 @@
def recordsFromQuery(expressions, operand=Operand.AND):
"""
+ Find records matching a query consisting of an interable of
+ expressions and an L{Operand}.
@return: a deferred iterable of matching L{IDirectoryRecord}s.
- @raises: L{QueryNotSupportedError} is the query is not
+ @raises: L{QueryNotSupportedError} if the query is not
supported by this directory service.
"""
+ def recordsWithFieldValue(fieldName, value):
+ """
+ Find records that have the given L{FieldName} with the given
+ value.
+ @return: an iterable of L{IDirectoryRecord}s.
+ """
+ def recordWithUID(uid):
+ """
+ Find the record that has the given L{FieldName.uid}.
+ @return: an iterable of L{IDirectoryRecord}s, or C{None} if
+ there is no such record.
+ """
+
+ def recordWithGUID(guid):
+ """
+ Find the record that has the given L{FieldName.guid}.
+ @return: an iterable of L{IDirectoryRecord}s, or C{None} if
+ there is no such record.
+ """
+ def recordsWithRecordType(recordType):
+ """
+ Find the records that have the given L{RecordType}.
+ @return: an iterable of L{IDirectoryRecord}s.
+ """
+
+ def recordWithShortName(recordType, shortName):
+ """
+ Find the record that has the given L{RecordType} and
+ L{FieldName.shortName}.
+ @return: an iterable of L{IDirectoryRecord}s, or C{None} if
+ there is no such record.
+ """
+
+ def recordsWithEmailAddress(emailAddress):
+ """
+ Find the records that have the given L{FieldName.emailAddress}.
+ @return: an iterable of L{IDirectoryRecord}s, or C{None} if
+ there is no such record.
+ """
+
+
+
class IDirectoryRecord(Interface):
"""
Directory record.
Modified: CalendarServer/trunk/twext/who/test/test_directory.py
===================================================================
--- CalendarServer/trunk/twext/who/test/test_directory.py 2013-02-01 16:30:18 UTC (rev 10616)
+++ CalendarServer/trunk/twext/who/test/test_directory.py 2013-02-01 17:46:16 UTC (rev 10617)
@@ -21,6 +21,7 @@
from zope.interface.verify import verifyObject, BrokenMethodImplementation
from twisted.trial import unittest
+from twisted.trial.unittest import SkipTest
from twext.who.idirectory import QueryNotSupportedError
from twext.who.idirectory import RecordType, FieldName
@@ -32,6 +33,7 @@
class BaseTest(unittest.TestCase):
realmName = "xyzzy"
+
def _testService(self):
if not hasattr(self, "_service"):
self._service = DirectoryService(self.realmName)
@@ -47,10 +49,12 @@
except BrokenMethodImplementation, e:
self.fail(e)
+
def test_init(self):
service = self._testService()
self.assertEquals(service.realmName, self.realmName)
+
def test_recordTypes(self):
service = self._testService()
self.assertEquals(
@@ -58,18 +62,36 @@
set(service.RecordTypeClass.iterconstants())
)
+
def test_recordsFromQueryNone(self):
service = self._testService()
records = service.recordsFromQuery(())
for record in records:
self.failTest("No records expected")
+
def test_recordsFromQueryBogus(self):
service = self._testService()
self.assertRaises(QueryNotSupportedError, service.recordsFromQuery, (object(),))
+ def test_recordWithUID(self):
+ raise SkipTest("Subclasses should implement this test.")
+ def test_recordWithGUID(self):
+ raise SkipTest("Subclasses should implement this test.")
+
+ def test_recordsWithRecordType(self):
+ raise SkipTest("Subclasses should implement this test.")
+
+ def test_recordWithShortName(self):
+ raise SkipTest("Subclasses should implement this test.")
+
+ def test_recordsWithEmailAddress(self):
+ raise SkipTest("Subclasses should implement this test.")
+
+
+
class DirectoryRecordTest(BaseTest):
fields_wsanchez = {
FieldName.uid: "wsanchez",
@@ -87,6 +109,7 @@
FieldName.emailAddresses: ("glyph at calendarserver.org",)
}
+
def _testRecord(self, fields=None, service=None):
if fields is None:
fields = self.fields_wsanchez
@@ -94,6 +117,7 @@
service = self._testService()
return DirectoryRecord(service, fields)
+
def test_interface(self):
record = self._testRecord()
try:
@@ -101,6 +125,7 @@
except BrokenMethodImplementation, e:
self.fail(e)
+
def test_init(self):
service = self._testService()
wsanchez = self._testRecord(self.fields_wsanchez)
@@ -108,6 +133,7 @@
self.assertEquals(wsanchez.service, service)
self.assertEquals(wsanchez.fields , self.fields_wsanchez)
+
def test_initWithNoUID(self):
fields = self.fields_wsanchez.copy()
del fields[FieldName.uid]
@@ -117,6 +143,7 @@
fields[FieldName.uid] = ""
self.assertRaises(ValueError, self._testRecord, fields)
+
def test_initWithNoRecordType(self):
fields = self.fields_wsanchez.copy()
del fields[FieldName.recordType]
@@ -126,6 +153,7 @@
fields[FieldName.recordType] = ""
self.assertRaises(ValueError, self._testRecord, fields)
+
def test_initWithNoShortNames(self):
fields = self.fields_wsanchez.copy()
del fields[FieldName.shortNames]
@@ -143,11 +171,13 @@
fields[FieldName.shortNames] = ("wsanchez", "")
self.assertRaises(ValueError, self._testRecord, fields)
+
def test_initWithBogusRecordType(self):
fields = self.fields_wsanchez.copy()
fields[FieldName.recordType] = object()
self.assertRaises(ValueError, self._testRecord, fields)
+
def test_compare(self):
fields_glyphmod = self.fields_glyph.copy()
del fields_glyphmod[FieldName.emailAddresses]
@@ -163,6 +193,7 @@
self.assertNotEqual(glyphmod, wsanchez)
self.assertNotEqual(wsanchez, wsanchezmod) # Different service
+
def test_attributeAccess(self):
wsanchez = self._testRecord(self.fields_wsanchez)
Modified: CalendarServer/trunk/twext/who/test/test_xml.py
===================================================================
--- CalendarServer/trunk/twext/who/test/test_xml.py 2013-02-01 16:30:18 UTC (rev 10616)
+++ CalendarServer/trunk/twext/who/test/test_xml.py 2013-02-01 17:46:16 UTC (rev 10617)
@@ -19,6 +19,8 @@
"""
from twisted.python.filepath import FilePath
+
+from twext.who.idirectory import RecordType
from twext.who.xml import DirectoryService
from twext.who.test import test_directory
@@ -67,7 +69,37 @@
class DirectoryServiceTest(BaseTest, test_directory.DirectoryServiceTest):
- def test_XYZZY(self):
+ def test_recordWithUID(self):
service = self._testService()
+ record = service.recordWithUID("wsanchez")
+ self.assertEquals(record.uid, "wsanchez")
- service.loadRecords()
+
+ def test_recordWithGUID(self):
+ service = self._testService()
+ record = service.recordWithGUID("wsanchez")
+ self.assertEquals(record, None)
+
+
+ def test_recordsWithRecordType(self):
+ service = self._testService()
+ records = service.recordsWithRecordType(RecordType.user)
+ self.assertEquals(
+ set((record.uid for record in records)),
+ set(("wsanchez", "glyph")),
+ )
+
+
+ def test_recordWithShortName(self):
+ service = self._testService()
+ record = service.recordWithShortName(RecordType.user, "wsanchez")
+ self.assertEquals(record.uid, "wsanchez")
+
+
+ def test_recordsWithEmailAddress(self):
+ service = self._testService()
+ records = service.recordsWithEmailAddress("wsanchez at example.com")
+ self.assertEquals(
+ set((record.uid for record in records)),
+ set(("wsanchez",)),
+ )
Modified: CalendarServer/trunk/twext/who/xml.py
===================================================================
--- CalendarServer/trunk/twext/who/xml.py 2013-02-01 16:30:18 UTC (rev 10616)
+++ CalendarServer/trunk/twext/who/xml.py 2013-02-01 17:46:16 UTC (rev 10617)
@@ -32,6 +32,7 @@
from twext.who.idirectory import DirectoryServiceError
from twext.who.idirectory import RecordType, FieldName
+from twext.who.idirectory import MatchType
from twext.who.idirectory import DirectoryQueryMatchExpression
from twext.who.directory import DirectoryService as BaseDirectoryService
from twext.who.directory import DirectoryRecord
@@ -240,8 +241,22 @@
self._index = index
+ def indexedRecordsFromMatchExpression(self, expression):
+ if expression.matchType != MatchType.equals:
+ raise NotImplementedError("Handle MatchType != equals")
+
+ if expression.flags:
+ raise NotImplementedError("Handle QueryFlags")
+
+ return self.index[expression.fieldName].get(expression.fieldValue, ())
+
+
def recordsFromExpression(self, expression):
if isinstance(expression, DirectoryQueryMatchExpression):
- raise NotImplementedError()
+ if expression.fieldName in self.indexedFields:
+ return self.indexedRecordsFromMatchExpression(expression)
+
+ raise NotImplementedError("Handle unindexed field")
+
else:
return BaseDirectoryService.recordsFromExpression(self, expression)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130201/5a3fcba5/attachment-0001.html>
More information about the calendarserver-changes
mailing list