[CalendarServer-changes] [11909] CalendarServer/trunk/twext/who
source_changes at macosforge.org
source_changes at macosforge.org
Wed Mar 12 11:20:19 PDT 2014
Revision: 11909
http://trac.calendarserver.org//changeset/11909
Author: wsanchez at apple.com
Date: 2013-11-07 18:14:21 -0800 (Thu, 07 Nov 2013)
Log Message:
-----------
Replace recordsFromQuery() with recordsFromExpression() that can handle a CompoundExpression.
Modified Paths:
--------------
CalendarServer/trunk/twext/who/aggregate.py
CalendarServer/trunk/twext/who/directory.py
CalendarServer/trunk/twext/who/idirectory.py
CalendarServer/trunk/twext/who/index.py
CalendarServer/trunk/twext/who/test/test_directory.py
CalendarServer/trunk/twext/who/test/test_xml.py
Modified: CalendarServer/trunk/twext/who/aggregate.py
===================================================================
--- CalendarServer/trunk/twext/who/aggregate.py 2013-11-08 00:36:07 UTC (rev 11908)
+++ CalendarServer/trunk/twext/who/aggregate.py 2013-11-08 02:14:21 UTC (rev 11909)
@@ -78,10 +78,10 @@
return self._recordType
- def recordsFromExpression(self, expression, records=None):
+ def recordsFromExpression(self, expression):
ds = []
for service in self.services:
- d = service.recordsFromExpression(expression, records)
+ d = service.recordsFromExpression(expression)
ds.append(d)
def unwrapFirstError(f):
Modified: CalendarServer/trunk/twext/who/directory.py
===================================================================
--- CalendarServer/trunk/twext/who/directory.py 2013-11-08 00:36:07 UTC (rev 11908)
+++ CalendarServer/trunk/twext/who/directory.py 2013-11-08 02:14:21 UTC (rev 11909)
@@ -33,7 +33,7 @@
from twext.who.idirectory import FieldName, RecordType
from twext.who.idirectory import Operand
from twext.who.idirectory import IDirectoryService, IDirectoryRecord
-from twext.who.expression import MatchExpression
+from twext.who.expression import CompoundExpression, MatchExpression
from twext.who.util import uniqueResult, describe
@@ -43,25 +43,30 @@
"""
Generic implementation of L{IDirectoryService}.
- This is a complete implementation of L{IDirectoryService}, with support for
- the query operands in L{Operand}.
+ Most of the C{recordsWith*} methods call L{recordsWithFieldValue}, which in
+ turn calls L{recordsFromExpression} with a corresponding
+ L{MatchExpression}.
- The C{recordsWith*} methods are all implemented in terms of
- L{recordsWithFieldValue}, which is in turn implemented in terms of
- L{recordsFromExpression}.
- L{recordsFromQuery} is also implemented in terms of
- {recordsFromExpression}.
+ L{recordsFromExpression} relies on L{recordsFromNonCompoundExpression} for
+ all expression types other than L{CompoundExpression}, which it handles
+ directly.
- L{recordsFromExpression} (and therefore most uses of the other methods)
- will always fail with a L{QueryNotSupportedError}.
+ L{recordsFromNonCompoundExpression} (and therefore most uses of the other
+ methods) will always fail with a L{QueryNotSupportedError}.
- A subclass should therefore override L{recordsFromExpression} with an
- implementation that handles any queries that it can support and its
- superclass' implementation with any query it cannot support.
+ A subclass should therefore override L{recordsFromNonCompoundExpression}
+ with an implementation that handles any queries that it can support (which
+ should include L{MatchExpression}) and calls its superclass' implementation
+ with any query it cannot support.
- A subclass may override L{recordsFromQuery} if it is to support additional
- operands.
+ A subclass may override L{recordsFromExpression} if it is to support
+ L{CompoundExpression}s with operands other than L{Operand.AND} and
+ L{Operand.OR}.
+ A subclass may override L{recordsFromExpression} if it is built on top
+ of a directory service that supports compound expressions, as that may be
+ more effient than relying on L{DirectoryService}'s implementation.
+
L{updateRecords} and L{removeRecords} will fail with L{NotAllowedError}
when asked to modify data.
A subclass should override these methods if is to allow editing of
@@ -108,20 +113,19 @@
return self.recordType.iterconstants()
- def recordsFromExpression(self, expression, records=None):
+ def recordsFromNonCompoundExpression(self, expression, records=None):
"""
- Finds records matching a single expression.
+ Finds records matching a expression.
- @note: The implementation in L{DirectoryService} always raises
- L{QueryNotSupportedError}.
+ @note: This method is called by L{recordsFromExpression} to handle
+ all expressions other than L{CompoundExpression}.
+ This implementation always fails with L{QueryNotSupportedError}.
+ Subclasses should override this in order to handle additional
+ expression types, and call on the superclass' implementation
+ for other expression types.
- @note: This L{DirectoryService} adds a C{records} keyword argument to
- the interface defined by L{IDirectoryService}.
- This allows the implementation of
- L{DirectoryService.recordsFromQuery} to narrow the scope of records
- being searched as it applies expressions.
- This is therefore relevant to subclasses, which need to support the
- added parameter, but not to users of L{IDirectoryService}.
+ @note: This interface is the same as L{recordsFromExpression}, except
+ for the additional C{records} argument.
@param expression: an expression to apply
@type expression: L{object}
@@ -142,44 +146,55 @@
@inlineCallbacks
- def recordsFromQuery(self, expressions, operand=Operand.AND):
- expressionIterator = iter(expressions)
+ def recordsFromExpression(self, expression):
+ if isinstance(expression, CompoundExpression):
+ operand = expression.operand
+ subExpressions = iter(expression.expressions)
- try:
- expression = expressionIterator.next()
- except StopIteration:
- returnValue(())
+ try:
+ subExpression = subExpressions.next()
+ except StopIteration:
+ returnValue(())
- results = set((yield self.recordsFromExpression(expression)))
+ results = set((
+ yield self.recordsFromNonCompoundExpression(subExpression)
+ ))
- for expression in expressions:
- if operand == Operand.AND:
- if not results:
- # No need to bother continuing here
- returnValue(())
+ for subExpression in subExpressions:
+ if operand == Operand.AND:
+ if not results:
+ # No need to bother continuing here
+ returnValue(())
- records = results
- else:
- records = None
+ records = results
+ else:
+ records = None
- recordsMatchingExpression = frozenset((
- yield self.recordsFromExpression(expression, records=records)
- ))
+ recordsMatchingExpression = frozenset((
+ yield self.recordsFromNonCompoundExpression(
+ subExpression,
+ records=records
+ )
+ ))
- if operand == Operand.AND:
- results &= recordsMatchingExpression
- elif operand == Operand.OR:
- results |= recordsMatchingExpression
- else:
- raise QueryNotSupportedError(
- "Unknown operand: {0}".format(operand)
- )
+ if operand == Operand.AND:
+ results &= recordsMatchingExpression
+ elif operand == Operand.OR:
+ results |= recordsMatchingExpression
+ else:
+ raise QueryNotSupportedError(
+ "Unknown operand: {0}".format(operand)
+ )
+ else:
+ results = yield self.recordsFromNonCompoundExpression(expression)
returnValue(results)
def recordsWithFieldValue(self, fieldName, value):
- return self.recordsFromExpression(MatchExpression(fieldName, value))
+ return self.recordsFromExpression(
+ MatchExpression(fieldName, value)
+ )
@inlineCallbacks
@@ -202,10 +217,17 @@
@inlineCallbacks
def recordWithShortName(self, recordType, shortName):
- returnValue(uniqueResult((yield self.recordsFromQuery((
- MatchExpression(FieldName.recordType, recordType),
- MatchExpression(FieldName.shortNames, shortName),
- )))))
+ returnValue(uniqueResult((
+ yield self.recordsFromExpression(
+ CompoundExpression(
+ (
+ MatchExpression(FieldName.recordType, recordType),
+ MatchExpression(FieldName.shortNames, shortName),
+ ),
+ operand=Operand.AND
+ )
+ )
+ )))
def recordsWithEmailAddress(self, emailAddress):
Modified: CalendarServer/trunk/twext/who/idirectory.py
===================================================================
--- CalendarServer/trunk/twext/who/idirectory.py 2013-11-08 00:36:07 UTC (rev 11908)
+++ CalendarServer/trunk/twext/who/idirectory.py 2013-11-08 02:14:21 UTC (rev 11909)
@@ -249,7 +249,7 @@
"""
- def recordsFromExpression(self, expression):
+ def recordsFromExpression(expression):
"""
Find records matching an expression.
@@ -264,25 +264,6 @@
"""
- def recordsFromQuery(expressions, operand=Operand.AND):
- """
- Find records by composing a query consisting of an iterable of
- expressions and an operand.
-
- @param expressions: expressions to query against
- @type expressions: iterable of L{object}s
-
- @param operand: an operand
- @type operand: a L{NamedConstant}
-
- @return: The matching records.
- @rtype: deferred iterable of L{IDirectoryRecord}s
-
- @raises: L{QueryNotSupportedError} if the query is not
- supported by this directory service.
- """
-
-
def recordsWithFieldValue(fieldName, value):
"""
Find records that have the given field name with the given
Modified: CalendarServer/trunk/twext/who/index.py
===================================================================
--- CalendarServer/trunk/twext/who/index.py 2013-11-08 00:36:07 UTC (rev 11908)
+++ CalendarServer/trunk/twext/who/index.py 2013-11-08 02:14:21 UTC (rev 11909)
@@ -215,7 +215,7 @@
return succeed(result)
- def recordsFromExpression(self, expression, records=None):
+ def recordsFromNonCompoundExpression(self, expression, records=None):
if isinstance(expression, MatchExpression):
if expression.fieldName in self.indexedFields:
return self.indexedRecordsFromMatchExpression(
@@ -226,7 +226,7 @@
expression, records=records
)
else:
- return BaseDirectoryService.recordsFromExpression(
+ return BaseDirectoryService.recordsFromNonCompoundExpression(
self, expression, records=records
)
Modified: CalendarServer/trunk/twext/who/test/test_directory.py
===================================================================
--- CalendarServer/trunk/twext/who/test/test_directory.py 2013-11-08 00:36:07 UTC (rev 11908)
+++ CalendarServer/trunk/twext/who/test/test_directory.py 2013-11-08 02:14:21 UTC (rev 11909)
@@ -27,10 +27,10 @@
from twext.who.idirectory import QueryNotSupportedError, NotAllowedError
from twext.who.idirectory import RecordType, FieldName
from twext.who.idirectory import IDirectoryService, IDirectoryRecord
+from twext.who.expression import CompoundExpression
from twext.who.directory import DirectoryService, DirectoryRecord
-
class ServiceMixIn(object):
realmName = u"xyzzy"
@@ -69,20 +69,20 @@
)
- @inlineCallbacks
- def test_recordsFromQueryNone(self):
- service = self.service()
- records = (yield service.recordsFromQuery(()))
- for record in records:
- self.failTest("No records expected")
+ # @inlineCallbacks
+ # def test_recordsFromExpressionNone(self):
+ # service = self.service()
+ # records = (yield service.recordsFromExpression(CompoundExpression()))
+ # for record in records:
+ # self.failTest("No records expected")
- def test_recordsFromQueryBogus(self):
- service = self.service()
- self.assertFailure(
- service.recordsFromQuery((object(),)),
- QueryNotSupportedError
- )
+ # def test_recordsFromExpressionBogus(self):
+ # service = self.service()
+ # self.assertFailure(
+ # service.recordsFromQuery(CompoundExpression(object(),)),
+ # QueryNotSupportedError
+ # )
def test_recordWithUID(self):
Modified: CalendarServer/trunk/twext/who/test/test_xml.py
===================================================================
--- CalendarServer/trunk/twext/who/test/test_xml.py 2013-11-08 00:36:07 UTC (rev 11908)
+++ CalendarServer/trunk/twext/who/test/test_xml.py 2013-11-08 02:14:21 UTC (rev 11909)
@@ -27,6 +27,7 @@
from twext.who.idirectory import NoSuchRecordError
from twext.who.idirectory import Operand
+from twext.who.expression import CompoundExpression
from twext.who.expression import MatchExpression, MatchType, MatchFlags
from twext.who.xml import ParseError
from twext.who.xml import DirectoryService, DirectoryRecord
@@ -300,12 +301,14 @@
@inlineCallbacks
def test_queryAnd(self):
service = self.service()
- records = yield service.recordsFromQuery(
- (
- service.query(u"emailAddresses", u"shared at example.com"),
- service.query(u"shortNames", u"sagen"),
- ),
- operand=Operand.AND
+ records = yield service.recordsFromExpression(
+ CompoundExpression(
+ (
+ service.query(u"emailAddresses", u"shared at example.com"),
+ service.query(u"shortNames", u"sagen"),
+ ),
+ operand=Operand.AND
+ )
)
self.assertRecords(records, (u"__sagen__",))
@@ -316,12 +319,14 @@
Test optimized case, where first expression yields no results.
"""
service = self.service()
- records = yield service.recordsFromQuery(
- (
- service.query(u"emailAddresses", u"nobody at example.com"),
- service.query(u"shortNames", u"sagen"),
- ),
- operand=Operand.AND
+ records = yield service.recordsFromExpression(
+ CompoundExpression(
+ (
+ service.query(u"emailAddresses", u"nobody at example.com"),
+ service.query(u"shortNames", u"sagen"),
+ ),
+ operand=Operand.AND
+ )
)
self.assertRecords(records, ())
@@ -329,25 +334,37 @@
@inlineCallbacks
def test_queryOr(self):
service = self.service()
- records = yield service.recordsFromQuery(
- (
- service.query(u"emailAddresses", u"shared at example.com"),
- service.query(u"shortNames", u"wsanchez"),
- ),
- operand=Operand.OR
+ records = yield service.recordsFromExpression(
+ CompoundExpression(
+ (
+ service.query(u"emailAddresses", u"shared at example.com"),
+ service.query(u"shortNames", u"wsanchez"),
+ ),
+ operand=Operand.OR
+ )
)
- self.assertRecords(records, (u"__sagen__", u"__dre__", u"__wsanchez__"))
+ self.assertRecords(
+ records,
+ (u"__sagen__", u"__dre__", u"__wsanchez__")
+ )
@inlineCallbacks
def test_queryNot(self):
service = self.service()
- records = yield service.recordsFromQuery(
- (
- service.query(u"emailAddresses", u"shared at example.com"),
- service.query(u"shortNames", u"sagen", flags=MatchFlags.NOT),
- ),
- operand=Operand.AND
+ records = yield service.recordsFromExpression(
+ CompoundExpression(
+ (
+ service.query(
+ u"emailAddresses", u"shared at example.com"
+ ),
+ service.query(
+ u"shortNames", u"sagen",
+ flags=MatchFlags.NOT
+ ),
+ ),
+ operand=Operand.AND
+ )
)
self.assertRecords(records, (u"__dre__",))
@@ -355,15 +372,17 @@
@inlineCallbacks
def test_queryNotNoIndex(self):
service = self.service()
- records = yield service.recordsFromQuery(
- (
- service.query(u"emailAddresses", u"shared at example.com"),
- service.query(
- u"fullNames", u"Andre LaBranche",
- flags=MatchFlags.NOT
+ records = yield service.recordsFromExpression(
+ CompoundExpression(
+ (
+ service.query(u"emailAddresses", u"shared at example.com"),
+ service.query(
+ u"fullNames", u"Andre LaBranche",
+ flags=MatchFlags.NOT
+ ),
),
- ),
- operand=Operand.AND
+ operand=Operand.AND
+ )
)
self.assertRecords(records, (u"__sagen__",))
@@ -371,58 +390,61 @@
@inlineCallbacks
def test_queryCaseInsensitive(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"shortNames", u"SagEn",
flags=MatchFlags.caseInsensitive
- ),
- ))
+ )
+ )
self.assertRecords(records, (u"__sagen__",))
@inlineCallbacks
def test_queryCaseInsensitiveNoIndex(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"fullNames", u"moRGen SAGen",
flags=MatchFlags.caseInsensitive
- ),
- ))
+ )
+ )
self.assertRecords(records, (u"__sagen__",))
@inlineCallbacks
def test_queryStartsWith(self):
service = self.service()
- records = yield service.recordsFromQuery((
- service.query(u"shortNames", u"wil", matchType=MatchType.startsWith),
- ))
+ records = yield service.recordsFromExpression(
+ service.query(
+ u"shortNames", u"wil",
+ matchType=MatchType.startsWith
+ )
+ )
self.assertRecords(records, (u"__wsanchez__",))
@inlineCallbacks
def test_queryStartsWithNoIndex(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"fullNames", u"Wilfredo",
matchType=MatchType.startsWith
- ),
- ))
+ )
+ )
self.assertRecords(records, (u"__wsanchez__",))
@inlineCallbacks
def test_queryStartsWithNot(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"shortNames", u"w",
matchType=MatchType.startsWith,
flags=MatchFlags.NOT,
- ),
- ))
+ )
+ )
self.assertRecords(
records,
(
@@ -450,13 +472,13 @@
should NOT require that all match?
"""
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"shortNames", u"wil",
matchType=MatchType.startsWith,
flags=MatchFlags.NOT,
- ),
- ))
+ )
+ )
self.assertRecords(
records,
(
@@ -479,13 +501,13 @@
@inlineCallbacks
def test_queryStartsWithNotNoIndex(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"fullNames", u"Wilfredo",
matchType=MatchType.startsWith,
flags=MatchFlags.NOT,
- ),
- ))
+ )
+ )
self.assertRecords(
records,
(
@@ -507,60 +529,63 @@
@inlineCallbacks
def test_queryStartsWithCaseInsensitive(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"shortNames", u"WIL",
matchType=MatchType.startsWith,
flags=MatchFlags.caseInsensitive,
- ),
- ))
+ )
+ )
self.assertRecords(records, (u"__wsanchez__",))
@inlineCallbacks
def test_queryStartsWithCaseInsensitiveNoIndex(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"fullNames", u"wilfrEdo",
matchType=MatchType.startsWith,
flags=MatchFlags.caseInsensitive,
- ),
- ))
+ )
+ )
self.assertRecords(records, (u"__wsanchez__",))
@inlineCallbacks
def test_queryContains(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"shortNames", u"sanchez",
- matchType=MatchType.contains
- ),
- ))
+ matchType=MatchType.contains,
+ )
+ )
self.assertRecords(records, (u"__wsanchez__",))
@inlineCallbacks
def test_queryContainsNoIndex(self):
service = self.service()
- records = yield service.recordsFromQuery((
- service.query(u"fullNames", u"fred", matchType=MatchType.contains),
- ))
+ records = yield service.recordsFromExpression(
+ service.query(
+ u"fullNames", u"fred",
+ matchType=MatchType.contains,
+ )
+ )
self.assertRecords(records, (u"__wsanchez__",))
@inlineCallbacks
def test_queryContainsNot(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"shortNames", u"sanchez",
matchType=MatchType.contains,
flags=MatchFlags.NOT,
- ),
- ))
+ )
+ )
self.assertRecords(
records,
(
@@ -582,13 +607,13 @@
@inlineCallbacks
def test_queryContainsNotNoIndex(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"fullNames", u"fred",
matchType=MatchType.contains,
flags=MatchFlags.NOT,
- ),
- ))
+ )
+ )
self.assertRecords(
records,
(
@@ -610,26 +635,26 @@
@inlineCallbacks
def test_queryContainsCaseInsensitive(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"shortNames", u"Sanchez",
matchType=MatchType.contains,
flags=MatchFlags.caseInsensitive,
- ),
- ))
+ )
+ )
self.assertRecords(records, (u"__wsanchez__",))
@inlineCallbacks
def test_queryContainsCaseInsensitiveNoIndex(self):
service = self.service()
- records = yield service.recordsFromQuery((
+ records = yield service.recordsFromExpression(
service.query(
u"fullNames", u"frEdo",
matchType=MatchType.contains,
flags=MatchFlags.caseInsensitive,
- ),
- ))
+ )
+ )
self.assertRecords(records, (u"__wsanchez__",))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20140312/9a03fe96/attachment.html>
More information about the calendarserver-changes
mailing list