Enhancement #7559: tests on counts of items in multiple fields.

This commit is contained in:
Charles Haley 2010-11-27 14:03:05 +00:00
parent 9e756e0a96
commit be987eac40
2 changed files with 35 additions and 12 deletions

View File

@ -403,7 +403,7 @@ class ResultCache(SearchQueryParser): # {{{
'<=':[2, lambda r, q: r <= q] '<=':[2, lambda r, q: r <= q]
} }
def get_numeric_matches(self, location, query): def get_numeric_matches(self, location, query, val_func = None):
matches = set([]) matches = set([])
if len(query) == 0: if len(query) == 0:
return matches return matches
@ -419,7 +419,10 @@ class ResultCache(SearchQueryParser): # {{{
if relop is None: if relop is None:
(p, relop) = self.numeric_search_relops['='] (p, relop) = self.numeric_search_relops['=']
loc = self.field_metadata[location]['rec_index'] if val_func is None:
loc = self.field_metadata[location]['rec_index']
val_func = lambda item, loc=loc: item[loc]
dt = self.field_metadata[location]['datatype'] dt = self.field_metadata[location]['datatype']
if dt == 'int': if dt == 'int':
cast = (lambda x: int (x)) cast = (lambda x: int (x))
@ -430,6 +433,9 @@ class ResultCache(SearchQueryParser): # {{{
elif dt == 'float': elif dt == 'float':
cast = lambda x : float (x) cast = lambda x : float (x)
adjust = lambda x: x adjust = lambda x: x
else: # count operation
cast = (lambda x: int (x))
adjust = lambda x: x
if len(query) > 1: if len(query) > 1:
mult = query[-1:].lower() mult = query[-1:].lower()
@ -446,10 +452,11 @@ class ResultCache(SearchQueryParser): # {{{
for item in self._data: for item in self._data:
if item is None: if item is None:
continue continue
if not item[loc]: v = val_func(item)
if not v:
i = 0 i = 0
else: else:
i = adjust(item[loc]) i = adjust(v)
if relop(i, q): if relop(i, q):
matches.add(item[0]) matches.add(item[0])
return matches return matches
@ -467,15 +474,23 @@ class ResultCache(SearchQueryParser): # {{{
return matches return matches
raise ParseException(query, len(query), 'Recursive query group detected', self) raise ParseException(query, len(query), 'Recursive query group detected', self)
# take care of dates special case if location in self.field_metadata:
if location in self.field_metadata and \ fm = self.field_metadata[location]
self.field_metadata[location]['datatype'] == 'datetime': # take care of dates special case
return self.get_dates_matches(location, query.lower()) if fm['datatype'] == 'datetime':
return self.get_dates_matches(location, query.lower())
# take care of numbers special case # take care of numbers special case
if location in self.field_metadata and \ if fm['datatype'] in ('rating', 'int', 'float'):
self.field_metadata[location]['datatype'] in ('rating', 'int', 'float'): return self.get_numeric_matches(location, query.lower())
return self.get_numeric_matches(location, query.lower())
# take care of the 'count' operator for is_multiples
if fm['is_multiple'] and \
len(query) > 1 and query.startswith('#') and \
query[1:1] in '=<>!':
vf = lambda item, loc=fm['rec_index'], ms=fm['is_multiple']:\
len(item[loc].split(ms)) if item[loc] is not None else 0
return self.get_numeric_matches(location, query[1:], val_func=vf)
# everything else, or 'all' matches # everything else, or 'all' matches
matchkind = CONTAINS_MATCH matchkind = CONTAINS_MATCH

View File

@ -274,6 +274,14 @@ Searching for ``no`` or ``unchecked`` will find all books with ``No`` in the col
:guilabel:`Advanced Search Dialog` :guilabel:`Advanced Search Dialog`
You can test for the number of items in multiple-value columns, such as tags, formats, authors, and tags-like custom columns. This is done using a syntax very similar to numeric tests (discussed above), except that the relational operator begins with a ``#`` character. For example::
tags:#>3 will give you books with more than three tags
tags:#!=3 will give you books that do not have three tags
authors:#=1 will give you books with exactly one author
#cust:#<5 will give you books with less than five items in custom column #cust
formats:#>1 will give you books with more than one format
Saving searches Saving searches
----------------- -----------------