1) add true and false searches for identifiers

2) ensure identifier searches are case insensitive
3) updates to template_lang.rst and gui.rst
This commit is contained in:
Charles Haley 2011-03-01 16:52:35 +00:00
parent 06562f5fa3
commit 2296e6d497
3 changed files with 55 additions and 9 deletions

View File

@ -457,8 +457,14 @@ class ResultCache(SearchQueryParser): # {{{
loc = self.field_metadata[location]['rec_index']
for id_ in candidates:
item = self._data[id_]
if item is None or item[loc] is None:
if item is None:
continue
if item[loc] is None:
if valq == 'false':
matches.add(id_)
continue
pairs = [p.strip() for p in item[loc].split(',')]
for pair in pairs:
parts = pair.split(':')
@ -468,7 +474,14 @@ class ResultCache(SearchQueryParser): # {{{
v = parts[1:]
if keyq and not _match(keyq, k, keyq_mkind):
continue
if valq and not _match(valq, v, valq_mkind):
if valq:
if valq == 'true':
if not v:
continue
elif valq == 'false':
if v:
continue
elif not _match(valq, v, valq_mkind):
continue
matches.add(id_)
return matches
@ -484,6 +497,10 @@ class ResultCache(SearchQueryParser): # {{{
elif query.startswith('~'):
matchkind = REGEXP_MATCH
query = query[1:]
if matchkind != REGEXP_MATCH:
# leave case in regexps because it can be significant e.g. \S \W \D
query = icu_lower(query)
return matchkind, query
def get_matches(self, location, query, candidates=None,
@ -565,9 +582,6 @@ class ResultCache(SearchQueryParser): # {{{
candidates)
# everything else, or 'all' matches
matchkind, query = self._matchkind(query)
if matchkind != REGEXP_MATCH:
# leave case in regexps because it can be significant e.g. \S \W \D
query = icu_lower(query)
if not isinstance(query, unicode):
query = query.decode('utf-8')

View File

@ -338,7 +338,7 @@ You can build advanced search queries easily using the :guilabel:`Advanced Searc
clicking the button |sbi|.
Available fields for searching are: ``tag, title, author, publisher, series, series_index, rating, cover,
comments, format, isbn, date, pubdate, search, size`` and custom columns. If a device is plugged in, the
comments, format, identifiers, date, pubdate, search, size`` and custom columns. If a device is plugged in, the
``ondevice`` field becomes available. To find the search name for a custom column, hover your mouse over the
column header.
@ -385,6 +385,21 @@ with undefined values in the column. Searching for ``true`` will find all books
values in the column. Searching for ``yes`` or ``checked`` will find all books with ``Yes`` in the column.
Searching for ``no`` or ``unchecked`` will find all books with ``No`` in the column.
Hierarchical items (e.g. A.B.C) use an extended syntax to match initial parts of the hierarchy. This is done by adding a period between the exact match indicator (=) and the text. For example, the query ``tags:=.A`` will find the tags `A` and `A.B`, but will not find the tags `AA` or `AA.B`. The query ``tags:=.A.B`` will find the tags `A.B` and `A.C`, but not the tag `A`.
Identifiers (e.g., isbn, doi, lccn etc) also use an extended syntax. First, note that an identifier has the form ``key:value``, as in ``isbn:123456789``. The extended syntax permits you to specify independently which key and value to search for. Both the key and the value parts of the query can use `equality`, `contains`, or `regular expression` matches. Examples:
* ``identifiers:true`` will find books with any identifier.
* ``identifiers:false`` will find books with no identifier.
* ``identifiers:123`` will search for books with any key having a value containing `123`.
* ``identifiers:=123456789`` will search for books with any key having a value equal to `123456789`.
* ``identifiers:=isbn:`` and ``identifiers:isbn:true`` will find books with a key equal to isbn having any value
* ``identifiers:=isbn:false`` will find books with no key equal to isbn.
* ``identifiers:=isbn:123`` will find books with a key equal to isbn having a value containing `123`.
* ``identifiers:=isbn:=123456789`` will find books with a key equal to isbn having a value equal to `123456789`.
* ``identifiers:i:1`` will find books with a key containing an `i` having a value containing a `1`.
.. |sbi| image:: images/search_button.png
:align: middle

View File

@ -126,6 +126,7 @@ The functions available are:
* ``re(pattern, replacement)`` -- return the field after applying the regular expression. All instances of `pattern` are replaced with `replacement`. As in all of |app|, these are python-compatible regular expressions.
* ``shorten(left chars, middle text, right chars)`` -- Return a shortened version of the field, consisting of `left chars` characters from the beginning of the field, followed by `middle text`, followed by `right chars` characters from the end of the string. `Left chars` and `right chars` must be integers. For example, assume the title of the book is `Ancient English Laws in the Times of Ivanhoe`, and you want it to fit in a space of at most 15 characters. If you use ``{title:shorten(9,-,5)}``, the result will be `Ancient E-nhoe`. If the field's length is less than ``left chars`` + ``right chars`` + the length of ``middle text``, then the field will be used intact. For example, the title `The Dome` would not be changed.
* ``switch(pattern, value, pattern, value, ..., else_value)`` -- for each ``pattern, value`` pair, checks if the field matches the regular expression ``pattern`` and if so, returns that ``value``. If no ``pattern`` matches, then ``else_value`` is returned. You can have as many ``pattern, value`` pairs as you want.
* ``select(key)`` -- interpret the field as a comma-separated list of items, with the items being of the form "id:value". Find the pair with the id equal to key, and return the corresponding value. This function is particularly useful for extracting a value such as an isbn from the set of identifiers for a book.
* ``test(text if not empty, text if empty)`` -- return `text if not empty` if the field is not empty, otherwise return `text if empty`.
@ -143,6 +144,8 @@ Using functions in templates - template program mode
The template language program mode differs from single-function mode in that it permits you to write template expressions that refer to other metadata fields, modify values, and do arithmetic. It is a reasonably complete programming language.
You can use the functions documented above in template program mode. See below for details.
Beginning with an example, assume that you want your template to show the series for a book if it has one, otherwise show the value of a custom field #genre. You cannot do this in the basic language because you cannot make reference to another metadata field within a template expression. In program mode, you can. The following expression works::
{#series:'ifempty($, field('#genre'))'}
@ -203,7 +206,7 @@ For various values of series_index, the program returns:
* series_index == 2, result = ``prefix 2->eq suffix``
* series_index == 3, result = ``prefix 3->gt suffix``
All the functions listed under single-function mode can be used in program mode, noting that unlike the functions described below you must supply a first parameter providing the value the function is to act upon.
**All the functions listed under single-function mode can be used in program mode**. To do so, you must supply the value that the function is to act upon as the first parameter, in addition to the parameters documented above. For example, in program mode the parameters of the `test` function are ``test(x, text_if_not_empty, text_if_empty)``. The `x` parameter, which is the value to be tested, will almost always be a variable or a function call, often `field()`.
The following functions are available in addition to those described in single-function mode. Remember from the example above that the single-function mode functions require an additional first parameter specifying the field to operate on. With the exception of the ``id`` parameter of assign, all parameters can be statements (sequences of expressions):
@ -212,9 +215,23 @@ The following functions are available in addition to those described in single-f
* ``cmp(x, y, lt, eq, gt)`` -- compares x and y after converting both to numbers. Returns ``lt`` if x < y. Returns ``eq`` if x == y. Otherwise returns ``gt``.
* ``divide(x, y)`` -- returns x / y. Throws an exception if either x or y are not numbers.
* ``field(name)`` -- returns the metadata field named by ``name``.
* ``format_date(x, date_format)`` -- format_date(val, format_string) -- format the value, which must be a date field, using the format_string, returning a string. The formatting codes are::
d : the day as number without a leading zero (1 to 31)
dd : the day as number with a leading zero (01 to 31) '
ddd : the abbreviated localized day name (e.g. "Mon" to "Sun"). '
dddd : the long localized day name (e.g. "Monday" to "Sunday"). '
M : the month as number without a leading zero (1 to 12). '
MM : the month as number with a leading zero (01 to 12) '
MMM : the abbreviated localized month name (e.g. "Jan" to "Dec"). '
MMMM : the long localized month name (e.g. "January" to "December"). '
yy : the year as two digit number (00 to 99). '
yyyy : the year as four digit number.'
* ``eval(string)`` -- evaluates the string as a program, passing the local variables (those ``assign`` ed to). This permits using the template processor to construct complex results from local variables.
* ``multiply(x, y)`` -- returns x * y. Throws an exception if either x or y are not numbers.
* ``print(a, b, ...)`` -- prints the arguments to standard output. Unless you start calibre from the command line (``calibre-debug -g``), the output will go to a black hole.
* ``raw_field(name)`` -- returns the metadata field named by name without applying any formatting.
* ``strcat(a, b, ...)`` -- can take any number of arguments. Returns a string formed by concatenating all the arguments.
* ``strcmp(x, y, lt, eq, gt)`` -- does a case-insensitive comparison x and y as strings. Returns ``lt`` if x < y. Returns ``eq`` if x == y. Otherwise returns ``gt``.
* ``substr(str, start, end)`` -- returns the ``start``'th through the ``end``'th characters of ``str``. The first character in ``str`` is the zero'th character. If end is negative, then it indicates that many characters counting from the right. If end is zero, then it indicates the last character. For example, ``substr('12345', 1, 0)`` returns ``'2345'``, and ``substr('12345', 1, -1)`` returns ``'234'``.