mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix #759645 (Template can't access size)
This commit is contained in:
commit
5a40b8835a
@ -391,11 +391,11 @@ class ResultCache(SearchQueryParser): # {{{
|
|||||||
def build_numeric_relop_dict(self):
|
def build_numeric_relop_dict(self):
|
||||||
self.numeric_search_relops = {
|
self.numeric_search_relops = {
|
||||||
'=':[1, lambda r, q: r == q],
|
'=':[1, lambda r, q: r == q],
|
||||||
'>':[1, lambda r, q: r > q],
|
'>':[1, lambda r, q: r is not None and r > q],
|
||||||
'<':[1, lambda r, q: r < q],
|
'<':[1, lambda r, q: r is not None and r < q],
|
||||||
'!=':[2, lambda r, q: r != q],
|
'!=':[2, lambda r, q: r != q],
|
||||||
'>=':[2, lambda r, q: r >= q],
|
'>=':[2, lambda r, q: r is not None and r >= q],
|
||||||
'<=':[2, lambda r, q: r <= q]
|
'<=':[2, lambda r, q: r is not None and r <= q]
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_numeric_matches(self, location, query, candidates, val_func = None):
|
def get_numeric_matches(self, location, query, candidates, val_func = None):
|
||||||
@ -406,17 +406,22 @@ class ResultCache(SearchQueryParser): # {{{
|
|||||||
if val_func is None:
|
if val_func is None:
|
||||||
loc = self.field_metadata[location]['rec_index']
|
loc = self.field_metadata[location]['rec_index']
|
||||||
val_func = lambda item, loc=loc: item[loc]
|
val_func = lambda item, loc=loc: item[loc]
|
||||||
|
dt = self.field_metadata[location]['datatype']
|
||||||
|
|
||||||
|
q = ''
|
||||||
|
val_func = lambda item, loc=loc: item[loc]
|
||||||
|
cast = adjust = lambda x: x
|
||||||
|
|
||||||
if query == 'false':
|
if query == 'false':
|
||||||
q = ''
|
if dt == 'rating':
|
||||||
relop = lambda x,y: x is None
|
relop = lambda x,y: not bool(x)
|
||||||
val_func = lambda item, loc=loc: item[loc]
|
else:
|
||||||
cast = adjust = lambda x: x
|
relop = lambda x,y: x is None
|
||||||
elif query == 'true':
|
elif query == 'true':
|
||||||
q = ''
|
if dt == 'rating':
|
||||||
relop = lambda x,y: x is not None
|
relop = lambda x,y: bool(x)
|
||||||
val_func = lambda item, loc=loc: item[loc]
|
else:
|
||||||
cast = adjust = lambda x: x
|
relop = lambda x,y: x is not None
|
||||||
else:
|
else:
|
||||||
relop = None
|
relop = None
|
||||||
for k in self.numeric_search_relops.keys():
|
for k in self.numeric_search_relops.keys():
|
||||||
@ -426,19 +431,15 @@ class ResultCache(SearchQueryParser): # {{{
|
|||||||
if relop is None:
|
if relop is None:
|
||||||
(p, relop) = self.numeric_search_relops['=']
|
(p, relop) = self.numeric_search_relops['=']
|
||||||
|
|
||||||
dt = self.field_metadata[location]['datatype']
|
|
||||||
if dt == 'int':
|
if dt == 'int':
|
||||||
cast = lambda x: int (x) if x is not None else None
|
|
||||||
adjust = lambda x: x
|
|
||||||
elif dt == 'rating':
|
|
||||||
cast = lambda x: int (x)
|
cast = lambda x: int (x)
|
||||||
|
elif dt == 'rating':
|
||||||
|
cast = lambda x: 0 if x is None else int (x)
|
||||||
adjust = lambda x: x/2
|
adjust = lambda x: x/2
|
||||||
elif dt in ('float', 'composite'):
|
elif dt in ('float', 'composite'):
|
||||||
cast = lambda x : float (x) if x is not None else None
|
cast = lambda x : float (x)
|
||||||
adjust = lambda x: x
|
|
||||||
else: # count operation
|
else: # count operation
|
||||||
cast = (lambda x: int (x))
|
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()
|
||||||
@ -450,7 +451,8 @@ class ResultCache(SearchQueryParser): # {{{
|
|||||||
try:
|
try:
|
||||||
q = cast(query) * mult
|
q = cast(query) * mult
|
||||||
except:
|
except:
|
||||||
return matches
|
raise ParseException(query, len(query),
|
||||||
|
'Non-numeric value in query', self)
|
||||||
|
|
||||||
for id_ in candidates:
|
for id_ in candidates:
|
||||||
item = self._data[id_]
|
item = self._data[id_]
|
||||||
@ -459,7 +461,7 @@ class ResultCache(SearchQueryParser): # {{{
|
|||||||
try:
|
try:
|
||||||
v = cast(val_func(item))
|
v = cast(val_func(item))
|
||||||
except:
|
except:
|
||||||
v = 0
|
v = None
|
||||||
if v:
|
if v:
|
||||||
v = adjust(v)
|
v = adjust(v)
|
||||||
if relop(v, q):
|
if relop(v, q):
|
||||||
@ -590,8 +592,7 @@ class ResultCache(SearchQueryParser): # {{{
|
|||||||
candidates = self.universal_set()
|
candidates = self.universal_set()
|
||||||
if len(candidates) == 0:
|
if len(candidates) == 0:
|
||||||
return matches
|
return matches
|
||||||
if location not in self.all_search_locations:
|
self.test_location_is_valid(location, query)
|
||||||
return matches
|
|
||||||
|
|
||||||
if len(location) > 2 and location.startswith('@') and \
|
if len(location) > 2 and location.startswith('@') and \
|
||||||
location[1:] in self.db_prefs['grouped_search_terms']:
|
location[1:] in self.db_prefs['grouped_search_terms']:
|
||||||
|
@ -854,6 +854,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
mi.uuid = row[fm['uuid']]
|
mi.uuid = row[fm['uuid']]
|
||||||
mi.title_sort = row[fm['sort']]
|
mi.title_sort = row[fm['sort']]
|
||||||
mi.last_modified = row[fm['last_modified']]
|
mi.last_modified = row[fm['last_modified']]
|
||||||
|
mi.size = row[fm['size']]
|
||||||
formats = row[fm['formats']]
|
formats = row[fm['formats']]
|
||||||
if not formats:
|
if not formats:
|
||||||
formats = None
|
formats = None
|
||||||
|
@ -20,7 +20,7 @@ import sys, string, operator
|
|||||||
|
|
||||||
from calibre.utils.pyparsing import CaselessKeyword, Group, Forward, \
|
from calibre.utils.pyparsing import CaselessKeyword, Group, Forward, \
|
||||||
CharsNotIn, Suppress, OneOrMore, MatchFirst, CaselessLiteral, \
|
CharsNotIn, Suppress, OneOrMore, MatchFirst, CaselessLiteral, \
|
||||||
Optional, NoMatch, ParseException, QuotedString
|
Optional, NoMatch, ParseException, QuotedString, Word
|
||||||
from calibre.constants import preferred_encoding
|
from calibre.constants import preferred_encoding
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.icu import sort_key
|
||||||
|
|
||||||
@ -128,12 +128,8 @@ class SearchQueryParser(object):
|
|||||||
self._tests_failed = False
|
self._tests_failed = False
|
||||||
self.optimize = optimize
|
self.optimize = optimize
|
||||||
# Define a token
|
# Define a token
|
||||||
standard_locations = map(lambda x : CaselessLiteral(x)+Suppress(':'),
|
self.standard_locations = locations
|
||||||
locations)
|
location = Optional(Word(string.ascii_letters+'#')+Suppress(':'), default='all')
|
||||||
location = NoMatch()
|
|
||||||
for l in standard_locations:
|
|
||||||
location |= l
|
|
||||||
location = Optional(location, default='all')
|
|
||||||
word_query = CharsNotIn(string.whitespace + '()')
|
word_query = CharsNotIn(string.whitespace + '()')
|
||||||
#quoted_query = Suppress('"')+CharsNotIn('"')+Suppress('"')
|
#quoted_query = Suppress('"')+CharsNotIn('"')+Suppress('"')
|
||||||
quoted_query = QuotedString('"', escChar='\\')
|
quoted_query = QuotedString('"', escChar='\\')
|
||||||
@ -250,7 +246,14 @@ class SearchQueryParser(object):
|
|||||||
raise ParseException(query, len(query), 'undefined saved search', self)
|
raise ParseException(query, len(query), 'undefined saved search', self)
|
||||||
return self._get_matches(location, query, candidates)
|
return self._get_matches(location, query, candidates)
|
||||||
|
|
||||||
|
def test_location_is_valid(self, location, query):
|
||||||
|
if location not in self.standard_locations:
|
||||||
|
raise ParseException(query, len(query),
|
||||||
|
_('No column exists with lookup name ') + location, self)
|
||||||
|
|
||||||
def _get_matches(self, location, query, candidates):
|
def _get_matches(self, location, query, candidates):
|
||||||
|
location = location.lower()
|
||||||
|
self.test_location_is_valid(location, query)
|
||||||
if self.optimize:
|
if self.optimize:
|
||||||
return self.get_matches(location, query, candidates=candidates)
|
return self.get_matches(location, query, candidates=candidates)
|
||||||
else:
|
else:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user