Fix #5244 (Add date: and pubdate: searches)

This commit is contained in:
Kovid Goyal 2010-04-09 10:07:11 +05:30
parent 2c37b1c36b
commit ebee2f795e
3 changed files with 91 additions and 5 deletions

View File

@ -10,7 +10,6 @@ import os, re, sys, shutil, cStringIO, glob, collections, textwrap, \
itertools, functools, traceback itertools, functools, traceback
from itertools import repeat from itertools import repeat
from math import floor from math import floor
from PyQt4.QtCore import QThread, QReadWriteLock from PyQt4.QtCore import QThread, QReadWriteLock
try: try:
from PIL import Image as PILImage from PIL import Image as PILImage
@ -33,7 +32,7 @@ from calibre.ptempfile import PersistentTemporaryFile
from calibre.customize.ui import run_plugins_on_import from calibre.customize.ui import run_plugins_on_import
from calibre.utils.filenames import ascii_filename from calibre.utils.filenames import ascii_filename
from calibre.utils.date import utcnow, now as nowf, utcfromtimestamp from calibre.utils.date import utcnow, now as nowf, utcfromtimestamp, parse_date
from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format from calibre.ebooks import BOOK_EXTENSIONS, check_ebook_format
if iswindows: if iswindows:
@ -196,10 +195,58 @@ class ResultCache(SearchQueryParser):
Stores sorted and filtered metadata in memory. Stores sorted and filtered metadata in memory.
''' '''
def build_relop_dict(self):
'''
Because the database dates have time in them, we can't use direct
comparisons even when field_count == 3. The query has time = 0, but
the database object has time == something. As such, a complete compare
will almost never be correct.
'''
def relop_eq(db, query, field_count):
if db.year == query.year:
if field_count == 1:
return True
if db.month == query.month:
if field_count == 2:
return True
return db.day == query.day
return False
def relop_gt(db, query, field_count):
if db.year > query.year:
return True
if field_count > 1 and db.year == query.year:
if db.month > query.month:
return True
return field_count == 3 and db.month == query.month and db.day > query.day
return False
def relop_lt(db, query, field_count):
if db.year < query.year:
return True
if field_count > 1 and db.year == query.year:
if db.month < query.month:
return True
return field_count == 3 and db.month == query.month and db.day < query.day
return False
def relop_ne(db, query, field_count):
return not relop_eq(db, query, field_count)
def relop_ge(db, query, field_count):
return not relop_lt(db, query, field_count)
def relop_le(db, query, field_count):
return not relop_gt(db, query, field_count)
self.search_relops = {'=':[1, relop_eq], '>':[1, relop_gt], '<':[1, relop_lt], \
'!=':[2, relop_ne], '>=':[2, relop_ge], '<=':[2, relop_le]}
def __init__(self): def __init__(self):
self._map = self._map_filtered = self._data = [] self._map = self._map_filtered = self._data = []
self.first_sort = True self.first_sort = True
SearchQueryParser.__init__(self) SearchQueryParser.__init__(self)
self.build_relop_dict()
def __getitem__(self, row): def __getitem__(self, row):
return self._data[self._map_filtered[row]] return self._data[self._map_filtered[row]]
@ -219,6 +266,27 @@ class ResultCache(SearchQueryParser):
if query and query.strip(): if query and query.strip():
location = location.lower().strip() location = location.lower().strip()
### take care of dates special case
if location in ('pubdate', 'date'):
if len(query) < 2:
return matches
relop = None
for k in self.search_relops.keys():
if query.startswith(k):
(p, relop) = self.search_relops[k]
query = query[p:]
if relop is None:
return matches
loc = FIELD_MAP[{'date':'timestamp', 'pubdate':'pubdate'}[location]]
qd = parse_date(query)
field_count = query.count('-') + 1
for item in self._data:
if item is None: continue
if relop(item[loc], qd, field_count):
matches.add(item[0])
return matches
### everything else
matchkind = CONTAINS_MATCH matchkind = CONTAINS_MATCH
if (len(query) > 1): if (len(query) > 1):
if query.startswith('\\'): if query.startswith('\\'):
@ -1994,6 +2062,3 @@ books_series_link feeds
self.refresh_ids(list(bad.keys())) self.refresh_ids(list(bad.keys()))
return bad return bad

View File

@ -207,6 +207,19 @@ Should you need to search for a string with a leading equals or tilde, prefix th
You can build advanced search queries easily using the :guilabel:`Advanced Search Dialog`, accessed by You can build advanced search queries easily using the :guilabel:`Advanced Search Dialog`, accessed by
clicking the button |sbi|. clicking the button |sbi|.
Available fields for searching are: ``tag, title, author, publisher, series, rating cover, comments, format,
isbn, date, pubdate, search``.
The syntax for searching for dates and publication dates is::
pubdate:>2000-1 Will find all books published after Jan, 2000
date:<=2000-1-3 Will find all books added to calibre beforre 3 Jan, 2000
pubdate:=2009 Will find all books published in 2009
The special field ``search`` is used for saved searches. So if you save a search with the name
"My spouse's books" you can enter ``search:"My spouses' books"`` in the search bar to reuse the saved
search. More about saving searches, below.
.. |sbi| image:: images/search_button.png .. |sbi| image:: images/search_button.png
:align: middle :align: middle
@ -214,6 +227,12 @@ clicking the button |sbi|.
:guilabel:`Advanced Search Dialog` :guilabel:`Advanced Search Dialog`
Saving searches
-----------------
|app| has a useful feature, it allows you to save a search you use frequently under a special name and then re-use that search with a single click. To do this, create your search, either by typing it in the search bar, or using the Tag Browser. Then, type the name you would like to give to the search in the Saved Searches box next to the search bar and click the plus icon next to the saved searches box to save the search.
Now, you can access your saved search in the Tga Browser under "Saved searches". A single click will allow you to re-use any arbitrarily comple search easily without needing to re-create it.
.. _configuration: .. _configuration:

View File

@ -98,6 +98,8 @@ class SearchQueryParser(object):
'format', 'format',
'isbn', 'isbn',
'search', 'search',
'date',
'pubdate',
'all', 'all',
] ]