mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Changes to better use FieldMetadata, plus rename of the class.
This commit is contained in:
parent
cb09c7ef46
commit
2ea3fdf5a7
@ -49,7 +49,7 @@ class TagCategories(QDialog, Ui_TagCategories):
|
||||
cc_map = self.db.custom_column_label_map
|
||||
for cc in cc_map:
|
||||
if cc_map[cc]['datatype'] == 'text':
|
||||
self.category_labels.append(db.tag_browser_categories.label_to_key(cc))
|
||||
self.category_labels.append(db.field_metadata.label_to_key(cc))
|
||||
category_icons.append(cc_icon)
|
||||
category_values.append(lambda col=cc: self.db.all_custom(label=col))
|
||||
category_names.append(cc_map[cc]['name'])
|
||||
|
@ -633,7 +633,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
if role == Qt.ToolTipRole:
|
||||
ht = self.column_map[section]
|
||||
if self.is_custom_column(self.column_map[section]):
|
||||
ht = self.db.tag_browser_categories.custom_field_prefix + ht
|
||||
ht = self.db.field_metadata.custom_field_prefix + ht
|
||||
if ht == 'timestamp': # change help text because users know this field as 'date'
|
||||
ht = 'date'
|
||||
return QVariant(_('The lookup/search name is "{0}"').format(ht))
|
||||
|
@ -224,7 +224,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
data = self.get_node_tree(config['sort_by_popularity'])
|
||||
self.root_item = TagTreeItem()
|
||||
for i, r in enumerate(self.row_map):
|
||||
if self.db.get_tag_browser_categories()[r]['kind'] != 'user':
|
||||
if self.db.field_metadata[r]['kind'] != 'user':
|
||||
tt = _('The lookup/search name is "{0}"').format(r)
|
||||
else:
|
||||
tt = ''
|
||||
@ -248,7 +248,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
||||
else:
|
||||
data = self.db.get_categories(sort_on_count=sort, icon_map=self.category_icon_map)
|
||||
|
||||
tb_categories = self.db.get_tag_browser_categories()
|
||||
tb_categories = self.db.field_metadata
|
||||
for category in tb_categories:
|
||||
if category in data: # They should always be there, but ...
|
||||
self.row_map.append(category)
|
||||
|
@ -150,14 +150,14 @@ class ResultCache(SearchQueryParser):
|
||||
'''
|
||||
Stores sorted and filtered metadata in memory.
|
||||
'''
|
||||
def __init__(self, FIELD_MAP, cc_label_map, tag_browser_categories):
|
||||
def __init__(self, FIELD_MAP, cc_label_map, field_metadata):
|
||||
self.FIELD_MAP = FIELD_MAP
|
||||
self.custom_column_label_map = cc_label_map
|
||||
self._map = self._map_filtered = self._data = []
|
||||
self.first_sort = True
|
||||
self.search_restriction = ''
|
||||
self.tag_browser_categories = tag_browser_categories
|
||||
self.all_search_locations = tag_browser_categories.get_search_keys()
|
||||
self.field_metadata = field_metadata
|
||||
self.all_search_locations = field_metadata.get_search_terms()
|
||||
SearchQueryParser.__init__(self, self.all_search_locations)
|
||||
self.build_date_relop_dict()
|
||||
self.build_numeric_relop_dict()
|
||||
@ -252,7 +252,7 @@ class ResultCache(SearchQueryParser):
|
||||
|
||||
if location == 'date':
|
||||
location = 'timestamp'
|
||||
loc = self.tag_browser_categories[location]['rec_index']
|
||||
loc = self.field_metadata[location]['rec_index']
|
||||
|
||||
if query == _('today'):
|
||||
qd = now()
|
||||
@ -311,8 +311,8 @@ class ResultCache(SearchQueryParser):
|
||||
if relop is None:
|
||||
(p, relop) = self.numeric_search_relops['=']
|
||||
|
||||
loc = self.tag_browser_categories[location]['rec_index']
|
||||
dt = self.tag_browser_categories[location]['datatype']
|
||||
loc = self.field_metadata[location]['rec_index']
|
||||
dt = self.field_metadata[location]['datatype']
|
||||
if dt == 'int':
|
||||
cast = (lambda x: int (x))
|
||||
adjust = lambda x: x
|
||||
@ -342,23 +342,21 @@ class ResultCache(SearchQueryParser):
|
||||
def get_matches(self, location, query):
|
||||
matches = set([])
|
||||
if query and query.strip():
|
||||
location = location.lower().strip()
|
||||
if location in ('tag', 'author', 'format', 'comment'):
|
||||
location += 's'
|
||||
# get metadata key associated with the search term. Eliminates
|
||||
# dealing with plurals and other aliases
|
||||
location = self.field_metadata.search_term_to_key(location.lower().strip())
|
||||
|
||||
### take care of dates special case
|
||||
if (location in ('pubdate', 'date')) or \
|
||||
(location in self.tag_browser_categories and \
|
||||
self.tag_browser_categories[location]['datatype'] == 'datetime'):
|
||||
# take care of dates special case
|
||||
if location in self.field_metadata and \
|
||||
self.field_metadata[location]['datatype'] == 'datetime':
|
||||
return self.get_dates_matches(location, query.lower())
|
||||
|
||||
### take care of numbers special case
|
||||
if location in self.tag_browser_categories and \
|
||||
self.tag_browser_categories[location]['datatype'] in \
|
||||
('rating', 'int', 'float'):
|
||||
# take care of numbers special case
|
||||
if location in self.field_metadata and \
|
||||
self.field_metadata[location]['datatype'] in ('rating', 'int', 'float'):
|
||||
return self.get_numeric_matches(location, query.lower())
|
||||
|
||||
### everything else, or 'all' matches
|
||||
# everything else, or 'all' matches
|
||||
matchkind = CONTAINS_MATCH
|
||||
if (len(query) > 1):
|
||||
if query.startswith('\\'):
|
||||
@ -377,25 +375,18 @@ class ResultCache(SearchQueryParser):
|
||||
query = query.decode('utf-8')
|
||||
|
||||
db_col = {}
|
||||
# fields to not check when matching against text.
|
||||
exclude_fields = []
|
||||
exclude_fields = [] # fields to not check when matching against text.
|
||||
col_datatype = []
|
||||
is_multiple_cols = {}
|
||||
for x in range(len(self.FIELD_MAP)):
|
||||
col_datatype.append('')
|
||||
for x in self.tag_browser_categories:
|
||||
if len(self.tag_browser_categories[x]['search_keys']):
|
||||
db_col[x] = self.tag_browser_categories[x]['rec_index']
|
||||
if self.tag_browser_categories[x]['datatype'] not in ['text', 'comments']:
|
||||
for x in self.field_metadata:
|
||||
if len(self.field_metadata[x]['search_terms']):
|
||||
db_col[x] = self.field_metadata[x]['rec_index']
|
||||
if self.field_metadata[x]['datatype'] not in ['text', 'comments']:
|
||||
exclude_fields.append(db_col[x])
|
||||
if self.tag_browser_categories.is_custom_field(x):
|
||||
col_datatype[db_col[x]] = self.tag_browser_categories[x]['datatype']
|
||||
# normal and custom ratings columns use the same code
|
||||
col_datatype[self.FIELD_MAP['rating']] = 'rating'
|
||||
|
||||
splitable_fields = [db_col['authors'], db_col['tags'], db_col['formats']]
|
||||
for x in self.tag_browser_categories.get_custom_fields():
|
||||
if self.tag_browser_categories[x]['is_multiple']:
|
||||
splitable_fields.append(db_col[x])
|
||||
col_datatype[db_col[x]] = self.field_metadata[x]['datatype']
|
||||
is_multiple_cols[db_col[x]] = self.field_metadata[x]['is_multiple']
|
||||
|
||||
try:
|
||||
rating_query = int(query) * 2
|
||||
@ -409,7 +400,7 @@ class ResultCache(SearchQueryParser):
|
||||
# get the tweak here so that the string lookup and compare aren't in the loop
|
||||
bools_are_tristate = tweaks['bool_custom_columns_are_tristate'] == 'yes'
|
||||
|
||||
for loc in location:
|
||||
for loc in location: # location is now an array of field indices
|
||||
if loc == db_col['authors']:
|
||||
### DB stores authors with commas changed to bars, so change query
|
||||
q = query.replace(',', '|');
|
||||
@ -460,7 +451,7 @@ class ResultCache(SearchQueryParser):
|
||||
continue
|
||||
|
||||
try: # a conversion below might fail
|
||||
# relationals not supported in 'all' queries
|
||||
# relationals are not supported in 'all' queries
|
||||
if col_datatype[loc] == 'float':
|
||||
if float(query) == item[loc]:
|
||||
matches.add(item[0])
|
||||
@ -474,12 +465,9 @@ class ResultCache(SearchQueryParser):
|
||||
# no further match is possible
|
||||
continue
|
||||
|
||||
if loc not in exclude_fields:
|
||||
if loc in splitable_fields:
|
||||
if col_datatype[loc]:
|
||||
vals = item[loc].split('|')
|
||||
else:
|
||||
vals = item[loc].split(',')
|
||||
if loc not in exclude_fields: # time for text matching
|
||||
if is_multiple_cols[loc] is not None:
|
||||
vals = item[loc].split(is_multiple_cols[loc])
|
||||
else:
|
||||
vals = [item[loc]] ### make into list to make _match happy
|
||||
if _match(q, vals, matchkind):
|
||||
|
@ -147,11 +147,15 @@ class CustomColumns(object):
|
||||
is_category = True
|
||||
else:
|
||||
is_category = False
|
||||
if v['is_multiple']:
|
||||
is_m = '|'
|
||||
else:
|
||||
is_m = None
|
||||
tn = 'custom_column_{0}'.format(v['num'])
|
||||
self.tag_browser_categories.add_custom_field(label=v['label'],
|
||||
self.field_metadata.add_custom_field(label=v['label'],
|
||||
table=tn, column='value', datatype=v['datatype'],
|
||||
is_multiple=v['is_multiple'], colnum=v['num'],
|
||||
name=v['name'], is_category=is_category)
|
||||
is_multiple=is_m, colnum=v['num'], name=v['name'],
|
||||
is_category=is_category)
|
||||
|
||||
def get_custom(self, idx, label=None, num=None, index_is_id=False):
|
||||
if label is not None:
|
||||
|
@ -116,7 +116,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
self.books_list_filter = self.conn.create_dynamic_filter('books_list_filter')
|
||||
|
||||
def __init__(self, library_path, row_factory=False):
|
||||
self.tag_browser_categories = FieldMetadata() #.get_tag_browser_categories()
|
||||
self.field_metadata = FieldMetadata()
|
||||
if not os.path.exists(library_path):
|
||||
os.makedirs(library_path)
|
||||
self.listeners = set([])
|
||||
@ -206,20 +206,20 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
'lccn':16, 'pubdate':17, 'flags':18, 'uuid':19}
|
||||
|
||||
for k,v in self.FIELD_MAP.iteritems():
|
||||
self.tag_browser_categories.set_field_record_index(k, v, prefer_custom=False)
|
||||
self.field_metadata.set_field_record_index(k, v, prefer_custom=False)
|
||||
|
||||
base = max(self.FIELD_MAP.values())
|
||||
for col in custom_cols:
|
||||
self.FIELD_MAP[col] = base = base+1
|
||||
self.tag_browser_categories.set_field_record_index(
|
||||
self.field_metadata.set_field_record_index(
|
||||
self.custom_column_num_map[col]['label'],
|
||||
base,
|
||||
prefer_custom=True)
|
||||
|
||||
self.FIELD_MAP['cover'] = base+1
|
||||
self.tag_browser_categories.set_field_record_index('cover', base+1, prefer_custom=False)
|
||||
self.field_metadata.set_field_record_index('cover', base+1, prefer_custom=False)
|
||||
self.FIELD_MAP['ondevice'] = base+2
|
||||
self.tag_browser_categories.set_field_record_index('ondevice', base+2, prefer_custom=False)
|
||||
self.field_metadata.set_field_record_index('ondevice', base+2, prefer_custom=False)
|
||||
|
||||
script = '''
|
||||
DROP VIEW IF EXISTS meta2;
|
||||
@ -233,7 +233,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
|
||||
self.book_on_device_func = None
|
||||
self.data = ResultCache(self.FIELD_MAP, self.custom_column_label_map,
|
||||
self.tag_browser_categories)
|
||||
self.field_metadata)
|
||||
self.search = self.data.search
|
||||
self.refresh = functools.partial(self.data.refresh, self)
|
||||
self.sort = self.data.sort
|
||||
@ -646,9 +646,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
def get_recipe(self, id):
|
||||
return self.conn.get('SELECT script FROM feeds WHERE id=?', (id,), all=False)
|
||||
|
||||
def get_tag_browser_categories(self):
|
||||
return self.tag_browser_categories
|
||||
|
||||
def get_categories(self, sort_on_count=False, ids=None, icon_map=None):
|
||||
self.books_list_filter.change([] if not ids else ids)
|
||||
|
||||
@ -656,9 +653,9 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
if icon_map is not None and type(icon_map) != TagsIcons:
|
||||
raise TypeError('icon_map passed to get_categories must be of type TagIcons')
|
||||
|
||||
tb_cats = self.tag_browser_categories
|
||||
tb_cats = self.field_metadata
|
||||
|
||||
# remove all user categories from tag_browser_categories. They can
|
||||
# remove all user categories from field_metadata. They can
|
||||
# easily come and go. We will add all the existing ones in below.
|
||||
for k in tb_cats.keys():
|
||||
if tb_cats[k]['kind'] in ['user', 'search']:
|
||||
|
@ -22,104 +22,252 @@ class TagsIcons(dict):
|
||||
self[a] = icon_dict[a]
|
||||
|
||||
class FieldMetadata(dict):
|
||||
'''
|
||||
key: the key to the dictionary is:
|
||||
- for standard fields, the metadata field name.
|
||||
- for custom fields, the metadata field name prefixed by '#'
|
||||
This is done to create two 'namespaces' so the names don't clash
|
||||
|
||||
# kind == standard: is tag category. May be a search label. Is db col
|
||||
# or is specially handled (e.g., news)
|
||||
# kind == not_cat: Is not a tag category. May be a search label. Is db col
|
||||
# kind == user: user-defined tag category
|
||||
# kind == search: saved-searches category
|
||||
# For 'standard', the order below is the order that the categories will
|
||||
# appear in the tags pane.
|
||||
#
|
||||
# label is the column label. key is either the label or in the case of
|
||||
# custom fields, the label prefixed with 'x'. Because of the prefixing,
|
||||
# there cannot be a name clash between standard and custom fields, so key
|
||||
# can be used as the metadata dictionary key.
|
||||
label: the actual column label. No prefixing.
|
||||
|
||||
category_items_ = [
|
||||
('authors', {'table':'authors', 'column':'name',
|
||||
'datatype':'text', 'is_multiple':False,
|
||||
'kind':'standard', 'name':_('Authors'),
|
||||
'search_keys':['authors', 'author'],
|
||||
'is_custom':False, 'is_category':True}),
|
||||
('series', {'table':'series', 'column':'name',
|
||||
'datatype':'text', 'is_multiple':False,
|
||||
'kind':'standard', 'name':_('Series'),
|
||||
'search_keys':['series'],
|
||||
'is_custom':False, 'is_category':True}),
|
||||
('formats', {'table':None, 'column':None,
|
||||
'datatype':'text', 'is_multiple':False, # must think what type this is!
|
||||
'kind':'standard', 'name':_('Formats'),
|
||||
'search_keys':['formats', 'format'],
|
||||
'is_custom':False, 'is_category':True}),
|
||||
('publisher', {'table':'publishers', 'column':'name',
|
||||
'datatype':'text', 'is_multiple':False,
|
||||
'kind':'standard', 'name':_('Publishers'),
|
||||
'search_keys':['publisher'],
|
||||
'is_custom':False, 'is_category':True}),
|
||||
('rating', {'table':'ratings', 'column':'rating',
|
||||
'datatype':'rating', 'is_multiple':False,
|
||||
'kind':'standard', 'name':_('Ratings'),
|
||||
'search_keys':['rating'],
|
||||
'is_custom':False, 'is_category':True}),
|
||||
('news', {'table':'news', 'column':'name',
|
||||
'datatype':None, 'is_multiple':False,
|
||||
'kind':'standard', 'name':_('News'),
|
||||
'search_keys':[],
|
||||
'is_custom':False, 'is_category':True}),
|
||||
('tags', {'table':'tags', 'column':'name',
|
||||
'datatype':'text', 'is_multiple':True,
|
||||
'kind':'standard', 'name':_('Tags'),
|
||||
'search_keys':['tags', 'tag'],
|
||||
'is_custom':False, 'is_category':True}),
|
||||
('author_sort',{'table':None, 'column':None, 'datatype':'text',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
('comments', {'table':None, 'column':None, 'datatype':'text',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':['comments', 'comment'], 'is_custom':False, 'is_category':False}),
|
||||
('cover', {'table':None, 'column':None, 'datatype':None,
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':['cover'], 'is_custom':False, 'is_category':False}),
|
||||
('flags', {'table':None, 'column':None, 'datatype':'text',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
('id', {'table':None, 'column':None, 'datatype':'int',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
('isbn', {'table':None, 'column':None, 'datatype':'text',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':['isbn'], 'is_custom':False, 'is_category':False}),
|
||||
('lccn', {'table':None, 'column':None, 'datatype':'text',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
('ondevice', {'table':None, 'column':None, 'datatype':'bool',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
('path', {'table':None, 'column':None, 'datatype':'text',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
('pubdate', {'table':None, 'column':None, 'datatype':'datetime',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':['pubdate'], 'is_custom':False, 'is_category':False}),
|
||||
('series_index',{'table':None, 'column':None, 'datatype':'float',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
('sort', {'table':None, 'column':None, 'datatype':'text',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
('size', {'table':None, 'column':None, 'datatype':'float',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
('timestamp', {'table':None, 'column':None, 'datatype':'datetime',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':['date'], 'is_custom':False, 'is_category':False}),
|
||||
('title', {'table':None, 'column':None, 'datatype':'text',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':['title'], 'is_custom':False, 'is_category':False}),
|
||||
('uuid', {'table':None, 'column':None, 'datatype':'text',
|
||||
'is_multiple':False, 'kind':'standard', 'name':None,
|
||||
'search_keys':[], 'is_custom':False, 'is_category':False}),
|
||||
datatype: the type of the information in the field. Valid values are float,
|
||||
int, rating, bool, comments, datetime, text.
|
||||
is_multiple: valid for the text datatype. If None, the field is to be
|
||||
treated as a single term. If not None, it contains a string, and the field
|
||||
is assumed to contain a list of terms separated by that string
|
||||
|
||||
kind == standard: is a db field.
|
||||
kind == category: standard tag category that isn't a field. see news.
|
||||
kind == user: user-defined tag category.
|
||||
kind == search: saved-searches category.
|
||||
|
||||
is_category: is a tag browser category. If true, then:
|
||||
table: name of the db table used to construct item list
|
||||
column: name of the column in the connection table to join on
|
||||
If these are None, then the category constructor must know how
|
||||
to build the item list (e.g., formats).
|
||||
The order below is the order that the categories will
|
||||
appear in the tags pane.
|
||||
|
||||
name: the text that is to be used when displaying the field. Column headings
|
||||
in the GUI, etc.
|
||||
|
||||
search_terms: the terms that can be used to identify the field when
|
||||
searching. They can be thought of as aliases for metadata keys, but are only
|
||||
valid when passed to search().
|
||||
|
||||
is_custom: the field has been added by the user.
|
||||
|
||||
rec_index: the index of the field in the db metadata record.
|
||||
|
||||
'''
|
||||
_field_metadata = [
|
||||
('authors', {'table':'authors',
|
||||
'column':'name',
|
||||
'datatype':'text',
|
||||
'is_multiple':',',
|
||||
'kind':'field',
|
||||
'name':_('Authors'),
|
||||
'search_terms':['authors', 'author'],
|
||||
'is_custom':False,
|
||||
'is_category':True}),
|
||||
('series', {'table':'series',
|
||||
'column':'name',
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':_('Series'),
|
||||
'search_terms':['series'],
|
||||
'is_custom':False,
|
||||
'is_category':True}),
|
||||
('formats', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':',',
|
||||
'kind':'field',
|
||||
'name':_('Formats'),
|
||||
'search_terms':['formats', 'format'],
|
||||
'is_custom':False,
|
||||
'is_category':True}),
|
||||
('publisher', {'table':'publishers',
|
||||
'column':'name',
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':_('Publishers'),
|
||||
'search_terms':['publisher'],
|
||||
'is_custom':False,
|
||||
'is_category':True}),
|
||||
('rating', {'table':'ratings',
|
||||
'column':'rating',
|
||||
'datatype':'rating',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':_('Ratings'),
|
||||
'search_terms':['rating'],
|
||||
'is_custom':False,
|
||||
'is_category':True}),
|
||||
('news', {'table':'news',
|
||||
'column':'name',
|
||||
'datatype':None,
|
||||
'is_multiple':None,
|
||||
'kind':'category',
|
||||
'name':_('News'),
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':True}),
|
||||
('tags', {'table':'tags',
|
||||
'column':'name',
|
||||
'datatype':'text',
|
||||
'is_multiple':',',
|
||||
'kind':'field',
|
||||
'name':_('Tags'),
|
||||
'search_terms':['tags', 'tag'],
|
||||
'is_custom':False,
|
||||
'is_category':True}),
|
||||
('author_sort',{'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('comments', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':['comments', 'comment'],
|
||||
'is_custom':False, 'is_category':False}),
|
||||
('cover', {'table':None,
|
||||
'column':None,
|
||||
'datatype':None,
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':['cover'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('flags', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('id', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'int',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('isbn', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':['isbn'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('lccn', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('ondevice', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'bool',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('path', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('pubdate', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'datetime',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':['pubdate'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('series_index',{'table':None,
|
||||
'column':None,
|
||||
'datatype':'float',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('sort', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('size', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'float',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('timestamp', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'datetime',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':['date'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('title', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':['title'],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
('uuid', {'table':None,
|
||||
'column':None,
|
||||
'datatype':'text',
|
||||
'is_multiple':None,
|
||||
'kind':'field',
|
||||
'name':None,
|
||||
'search_terms':[],
|
||||
'is_custom':False,
|
||||
'is_category':False}),
|
||||
]
|
||||
|
||||
# search labels that are not db columns
|
||||
@ -130,10 +278,13 @@ class FieldMetadata(dict):
|
||||
|
||||
def __init__(self):
|
||||
self._tb_cats = OrderedDict()
|
||||
for k,v in self.category_items_:
|
||||
self._search_term_map = {}
|
||||
self.custom_label_to_key_map = {}
|
||||
for k,v in self._field_metadata:
|
||||
self._tb_cats[k] = v
|
||||
self._tb_cats[k]['label'] = k # saved some typing above...
|
||||
self._add_search_terms_to_map(k, self._tb_cats[k]['search_terms'])
|
||||
self.custom_field_prefix = '#'
|
||||
|
||||
self.get = self._tb_cats.get
|
||||
|
||||
def __getitem__(self, key):
|
||||
@ -175,10 +326,14 @@ class FieldMetadata(dict):
|
||||
return self._tb_cats[key]['label']
|
||||
|
||||
def label_to_key(self, label, prefer_custom=False):
|
||||
if prefer_custom:
|
||||
if label in self.custom_label_to_key_map:
|
||||
return self.custom_label_to_key_map[label]
|
||||
if 'label' in self._tb_cats:
|
||||
return label
|
||||
if self.is_custom_field(label):
|
||||
return self.custom_field_prefix+label
|
||||
if not prefer_custom:
|
||||
if label in self.custom_label_to_key_map:
|
||||
return self.custom_label_to_key_map[label]
|
||||
raise ValueError('Unknown key [%s]'%(label))
|
||||
|
||||
def get_custom_fields(self):
|
||||
@ -186,15 +341,35 @@ class FieldMetadata(dict):
|
||||
|
||||
def add_custom_field(self, label, table, column, datatype, colnum,
|
||||
name, is_multiple, is_category):
|
||||
fn = self.custom_field_prefix + label
|
||||
if fn in self._tb_cats:
|
||||
key = self.custom_field_prefix + label
|
||||
if key in self._tb_cats:
|
||||
raise ValueError('Duplicate custom field [%s]'%(label))
|
||||
self._tb_cats[fn] = {'table':table, 'column':column,
|
||||
'datatype':datatype, 'is_multiple':is_multiple,
|
||||
'kind':'standard', 'name':name,
|
||||
'search_keys':[fn], 'label':label,
|
||||
'colnum':colnum, 'is_custom':True,
|
||||
self._tb_cats[key] = {'table':table, 'column':column,
|
||||
'datatype':datatype, 'is_multiple':is_multiple,
|
||||
'kind':'field', 'name':name,
|
||||
'search_terms':[key], 'label':label,
|
||||
'colnum':colnum, 'is_custom':True,
|
||||
'is_category':is_category}
|
||||
self._add_search_terms_to_map(key, [key])
|
||||
self.custom_label_to_key_map[label] = key
|
||||
|
||||
def add_user_category(self, label, name):
|
||||
if label in self._tb_cats:
|
||||
raise ValueError('Duplicate user field [%s]'%(label))
|
||||
self._tb_cats[label] = {'table':None, 'column':None,
|
||||
'datatype':None, 'is_multiple':None,
|
||||
'kind':'user', 'name':name,
|
||||
'search_terms':[], 'is_custom':False,
|
||||
'is_category':True}
|
||||
|
||||
def add_search_category(self, label, name):
|
||||
if label in self._tb_cats:
|
||||
raise ValueError('Duplicate user field [%s]'%(label))
|
||||
self._tb_cats[label] = {'table':None, 'column':None,
|
||||
'datatype':None, 'is_multiple':None,
|
||||
'kind':'search', 'name':name,
|
||||
'search_terms':[], 'is_custom':False,
|
||||
'is_category':True}
|
||||
|
||||
def set_field_record_index(self, label, index, prefer_custom=False):
|
||||
if prefer_custom:
|
||||
@ -208,23 +383,6 @@ class FieldMetadata(dict):
|
||||
key = self.custom_field_prefix+label
|
||||
self._tb_cats[key]['rec_index'] = index # let the exception fly ...
|
||||
|
||||
def add_user_category(self, label, name):
|
||||
if label in self._tb_cats:
|
||||
raise ValueError('Duplicate user field [%s]'%(label))
|
||||
self._tb_cats[label] = {'table':None, 'column':None,
|
||||
'datatype':None, 'is_multiple':False,
|
||||
'kind':'user', 'name':name,
|
||||
'search_keys':[], 'is_custom':False,
|
||||
'is_category':True}
|
||||
|
||||
def add_search_category(self, label, name):
|
||||
if label in self._tb_cats:
|
||||
raise ValueError('Duplicate user field [%s]'%(label))
|
||||
self._tb_cats[label] = {'table':None, 'column':None,
|
||||
'datatype':None, 'is_multiple':False,
|
||||
'kind':'search', 'name':name,
|
||||
'search_keys':[], 'is_custom':False,
|
||||
'is_category':True}
|
||||
|
||||
# DEFAULT_LOCATIONS = frozenset([
|
||||
# 'all',
|
||||
@ -248,14 +406,23 @@ class FieldMetadata(dict):
|
||||
# 'title',
|
||||
# ])
|
||||
|
||||
|
||||
def get_search_keys(self):
|
||||
def get_search_terms(self):
|
||||
s_keys = []
|
||||
for v in self._tb_cats.itervalues():
|
||||
map((lambda x:s_keys.append(x)), v['search_keys'])
|
||||
map((lambda x:s_keys.append(x)), v['search_terms'])
|
||||
for v in self.search_items:
|
||||
s_keys.append(v)
|
||||
# if set(s_keys) != self.DEFAULT_LOCATIONS:
|
||||
# print 'search labels and default_locations do not match:'
|
||||
# print set(s_keys) ^ self.DEFAULT_LOCATIONS
|
||||
return s_keys
|
||||
|
||||
def _add_search_terms_to_map(self, key, terms):
|
||||
if terms is not None:
|
||||
for t in terms:
|
||||
self._search_term_map[t] = key
|
||||
|
||||
def search_term_to_key(self, term):
|
||||
if term in self._search_term_map:
|
||||
return self._search_term_map[term]
|
||||
return term
|
||||
|
@ -289,6 +289,6 @@ class SchemaUpgrade(object):
|
||||
'''.format(tn=table_name, cn=column_name, vcn=view_column_name))
|
||||
self.conn.executescript(script)
|
||||
|
||||
for tn, cn in self.tag_browser_categories.items():
|
||||
for tn, cn in self.field_metadata.items():
|
||||
if tn != 'news':
|
||||
create_tag_browser_view(tn, cn[0], cn[1])
|
||||
|
@ -331,7 +331,7 @@ class OPDSServer(object):
|
||||
raise cherrypy.HTTPError(404, 'Not found')
|
||||
categories = self.categories_cache(
|
||||
self.get_opds_allowed_ids_for_version(version))
|
||||
category_meta = self.db.get_tag_browser_categories()
|
||||
category_meta = self.db.field_metadata
|
||||
cats = [
|
||||
(_('Newest'), _('Date'), 'Onewest'),
|
||||
(_('Title'), _('Title'), 'Otitle'),
|
||||
|
Loading…
x
Reference in New Issue
Block a user