Changes to better use FieldMetadata, plus rename of the class.

This commit is contained in:
Charles Haley 2010-05-27 13:27:05 +01:00
parent cb09c7ef46
commit 2ea3fdf5a7
9 changed files with 344 additions and 188 deletions

View File

@ -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'])

View File

@ -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))

View File

@ -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)

View File

@ -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):

View File

@ -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:

View File

@ -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']:

View File

@ -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

View File

@ -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])

View File

@ -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'),