def matchExpression(fieldName, matchString, matchType, matchFlags): # special case recordType field if fieldName == FieldName.recordType: # change kind to record type matchValue = vCardKindToRecordTypeMap.get(matchString.lower()) if matchValue is None: matchValue = NamedConstant() matchValue.description = u"" # change types and flags matchFlags &= ~MatchFlags.caseInsensitive matchType = MatchType.equals else: matchValue = matchString.decode("utf-8") return MatchExpression(fieldName, matchValue, matchType, matchFlags)
def doAddressBookDirectoryQuery(self, addressBookFilter, addressBookQuery, maxResults, defaultKind="individual"): """ Get vCards for a given addressBookFilter and addressBookQuery """ log.debug("doAddressBookDirectoryQuery: directory={directory} addressBookFilter={addressBookFilter}, addressBookQuery={addressBookQuery}, maxResults={maxResults}", directory=self.directory, addressBookFilter=addressBookFilter, addressBookQuery=addressBookQuery, maxResults=maxResults) results = [] limited = False maxQueryRecords = 0 vcardPropToRecordFieldMap = { "FN": FieldName.fullNames, "N": FieldName.fullNames, "EMAIL": FieldName.emailAddresses, "UID": FieldName.uid, "ADR": ( CalFieldName.streetAddress, CalFieldName.floor, ), "KIND": FieldName.recordType, # LATER "X-ADDRESSBOOKSERVER-MEMBER": FieldName.membersUIDs, } propNames, expression = expressionFromABFilter( addressBookFilter, vcardPropToRecordFieldMap, vCardConstantProperties, ) if expression: queryRecordType = None if "KIND" not in propNames: queryRecordType = vCardKindToRecordTypeMap.get(defaultKind) # if CompoundExpression of MatchExpression: recordsWithFieldValue() else recordsMatchingType() fields = [] if expression is not True: def fieldForMatchExpression(match): return ( match.fieldName.name, match.fieldValue, match.flags, match.matchType, ) if isinstance(expression, CompoundExpression): operand = expression.operand for match in expression.expressions: if isinstance(match, MatchExpression): if match.fieldName != FieldName.recordType: fields.append(fieldForMatchExpression(match)) # else optimize: collect record type list for query else: # do all record types query fields = [] break elif isinstance(expression, MatchExpression): operand = Operand.OR if expression.fieldName != FieldName.recordType: fields.append(fieldForMatchExpression(expression)) else: recordType = expression.fieldValue maxRecords = int(maxResults * 1.2) # keep trying query till we get results based on filter. Especially when doing "all results" query while True: queryLimited = False log.debug("doAddressBookDirectoryQuery: expression={expression!r}, propNames={propNames}", expression=expression, propNames=propNames) allRecords = set() if fields: records = yield self.directory.recordsMatchingFields(fields, operand, queryRecordType) log.debug("doAddressBookDirectoryQuery: recordsMatchingFields({f}, {o}): #records={n}, records={records!r}", f=fields, o=operand, n=len(records), records=records) allRecords = set(records) else: recordTypes = set([queryRecordType]) if queryRecordType else set(self.directory.recordTypes()) & set(recordTypeToVCardKindMap.keys()) for recordType in recordTypes: records = yield self.directory.recordsWithRecordType(recordType) log.debug("doAddressBookDirectoryQuery: #records={n}, records={records!r}", n=len(records), records=records) allRecords |= set(records) vCardsResults = [(yield ABDirectoryQueryResult(self).generate(record)) for record in allRecords] filteredResults = set() for vCardResult in vCardsResults: if addressBookFilter.match(vCardResult.vCard()): log.debug("doAddressBookDirectoryQuery: vCard did match filter:\n{vcard}", vcard=vCardResult.vCard()) filteredResults.add(vCardResult) else: log.debug("doAddressBookDirectoryQuery: vCard did not match filter:\n{vcard}", vcard=vCardResult.vCard()) #no more results if not queryLimited: break # more than requested results if maxResults and len(filteredResults) >= maxResults: break # more than max report results if len(filteredResults) >= config.MaxQueryWithDataResults: break # more than self limit if maxQueryRecords and maxRecords >= maxQueryRecords: break # try again with 2x maxRecords *= 2 if maxQueryRecords and maxRecords > maxQueryRecords: maxRecords = maxQueryRecords results = sorted(filteredResults, key=lambda result: result.vCard().propertyValue("UID")) limited = maxResults and len(results) >= maxResults log.info("limited={l} #results={n}", l=limited, n=len(results)) returnValue((results, limited,))
def doAddressBookDirectoryQuery(self, addressBookFilter, addressBookQuery, maxResults, defaultKind="individual"): """ Get vCards for a given addressBookFilter and addressBookQuery """ log.debug( "doAddressBookDirectoryQuery: directory={directory} addressBookFilter={addressBookFilter}, addressBookQuery={addressBookQuery}, maxResults={maxResults}", directory=self.directory, addressBookFilter=addressBookFilter, addressBookQuery=addressBookQuery, maxResults=maxResults) results = [] limited = False maxQueryRecords = 0 vcardPropToRecordFieldMap = { "FN": FieldName.fullNames, "N": FieldName.fullNames, "EMAIL": FieldName.emailAddresses, "UID": FieldName.uid, "ADR": ( CalFieldName.streetAddress, # CalFieldName.floor, ), "KIND": FieldName.recordType, # LATER "X-ADDRESSBOOKSERVER-MEMBER": FieldName.membersUIDs, } propNames, expression = expressionFromABFilter( addressBookFilter, vcardPropToRecordFieldMap, vCardConstantProperties, ) if expression: queryRecordType = None if "KIND" not in propNames: queryRecordType = vCardKindToRecordTypeMap.get(defaultKind) # if CompoundExpression of MatchExpression: recordsWithFieldValue() else recordsMatchingType() fields = [] if expression is not True: def fieldForMatchExpression(match): return ( match.fieldName.name, match.fieldValue, match.flags, match.matchType, ) if isinstance(expression, CompoundExpression): operand = expression.operand for match in expression.expressions: if isinstance(match, MatchExpression): if match.fieldName != FieldName.recordType: fields.append(fieldForMatchExpression(match)) # else optimize: collect record type list for query else: # do all record types query fields = [] break elif isinstance(expression, MatchExpression): operand = Operand.OR if expression.fieldName != FieldName.recordType: fields.append(fieldForMatchExpression(expression)) else: recordType = expression.fieldValue maxRecords = int(maxResults * 1.2) # keep trying query till we get results based on filter. Especially when doing "all results" query while True: queryLimited = False log.debug( "doAddressBookDirectoryQuery: expression={expression!r}, propNames={propNames}", expression=expression, propNames=propNames) allRecords = set() if fields: records = yield self.directory.recordsMatchingFields( fields, operand, queryRecordType) log.debug( "doAddressBookDirectoryQuery: recordsMatchingFields({f}, {o}): #records={n}, records={records!r}", f=fields, o=operand, n=len(records), records=records) allRecords = set(records) else: recordTypes = set([queryRecordType ]) if queryRecordType else set( self.directory.recordTypes()) & set( recordTypeToVCardKindMap.keys()) for recordType in recordTypes: records = yield self.directory.recordsWithRecordType( recordType) log.debug( "doAddressBookDirectoryQuery: #records={n}, records={records!r}", n=len(records), records=records) allRecords |= set(records) vCardsResults = [ (yield ABDirectoryQueryResult(self).generate(record)) for record in allRecords ] filteredResults = set() for vCardResult in vCardsResults: if addressBookFilter.match(vCardResult.vCard()): log.debug( "doAddressBookDirectoryQuery: vCard did match filter:\n{vcard}", vcard=vCardResult.vCard()) filteredResults.add(vCardResult) else: log.debug( "doAddressBookDirectoryQuery: vCard did not match filter:\n{vcard}", vcard=vCardResult.vCard()) # no more results if not queryLimited: break # more than requested results if maxResults and len(filteredResults) >= maxResults: break # more than max report results if len(filteredResults) >= config.MaxQueryWithDataResults: break # more than self limit if maxQueryRecords and maxRecords >= maxQueryRecords: break # try again with 2x maxRecords *= 2 if maxQueryRecords and maxRecords > maxQueryRecords: maxRecords = maxQueryRecords results = sorted( filteredResults, key=lambda result: result.vCard().propertyValue("UID")) limited = maxResults and len(results) >= maxResults log.info("limited={l} #results={n}", l=limited, n=len(results)) returnValue(( results, limited, ))