mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Make filtered views permanent
This commit is contained in:
parent
8153b33522
commit
f20255b98e
@ -526,7 +526,7 @@ class ResultCache(SearchQueryParser):
|
||||
self._map.sort(cmp=fcmp, reverse=not ascending)
|
||||
self._map_filtered = [id for id in self._map if id in self._map_filtered]
|
||||
|
||||
def search(self, query, return_matches = False):
|
||||
def search(self, query, return_matches=False):
|
||||
if not query or not query.strip():
|
||||
q = self.search_restriction
|
||||
else:
|
||||
|
@ -45,6 +45,7 @@ class CustomColumns(object):
|
||||
DROP TRIGGER IF EXISTS fkc_insert_{table};
|
||||
DROP TRIGGER IF EXISTS fkc_delete_{table};
|
||||
DROP VIEW IF EXISTS tag_browser_{table};
|
||||
DROP VIEW IF EXISTS tag_browser_filtered_{table};
|
||||
DROP TABLE IF EXISTS {table};
|
||||
DROP TABLE IF EXISTS {lt};
|
||||
'''.format(table=table, lt=lt)
|
||||
@ -137,7 +138,14 @@ class CustomColumns(object):
|
||||
'comments': lambda x,d: adapt_text(x, {'is_multiple':False}),
|
||||
'datetime' : adapt_datetime,
|
||||
'text':adapt_text
|
||||
}
|
||||
}
|
||||
|
||||
# Create Tag Browser categories for custom columns
|
||||
for i, v in self.custom_column_num_map.items():
|
||||
if v['normalized']:
|
||||
tn = 'custom_column_{0}'.format(i)
|
||||
self.tag_browser_categories[tn] = [v['label'], 'value']
|
||||
|
||||
|
||||
def get_custom(self, idx, label=None, num=None, index_is_id=False):
|
||||
if label is not None:
|
||||
@ -396,6 +404,13 @@ class CustomColumns(object):
|
||||
(SELECT COUNT(id) FROM {lt} WHERE value={table}.id) count
|
||||
FROM {table};
|
||||
|
||||
CREATE VIEW tag_browser_filtered_{table} AS SELECT
|
||||
id,
|
||||
value,
|
||||
(SELECT COUNT({lt}.id) FROM {lt} WHERE value={table}.id AND
|
||||
books_list_filter(book)) count
|
||||
FROM {table};
|
||||
|
||||
'''.format(lt=lt, table=table),
|
||||
|
||||
]
|
||||
|
@ -106,6 +106,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
self.conn = connect(self.dbpath, self.row_factory)
|
||||
if self.user_version == 0:
|
||||
self.initialize_database()
|
||||
self.books_list_filter = self.conn.create_dynamic_filter('books_list_filter')
|
||||
|
||||
def __init__(self, library_path, row_factory=False):
|
||||
if not os.path.exists(library_path):
|
||||
@ -118,6 +119,15 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
self.dbpath)
|
||||
if isinstance(self.dbpath, unicode):
|
||||
self.dbpath = self.dbpath.encode(filesystem_encoding)
|
||||
|
||||
self.tag_browser_categories = {
|
||||
'tags' : ['tag', 'name'],
|
||||
'series' : ['series', 'name'],
|
||||
'publishers': ['publisher', 'name'],
|
||||
'authors' : ['author', 'name'],
|
||||
'news' : ['news', 'name'],
|
||||
}
|
||||
|
||||
self.connect()
|
||||
self.is_case_sensitive = not iswindows and not isosx and \
|
||||
not os.path.exists(self.dbpath.replace('metadata.db', 'MeTAdAtA.dB'))
|
||||
@ -125,6 +135,30 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
self.initialize_dynamic()
|
||||
|
||||
def initialize_dynamic(self):
|
||||
self.conn.executescript(u'''
|
||||
CREATE TEMP VIEW IF NOT EXISTS tag_browser_news AS SELECT DISTINCT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id) count
|
||||
FROM tags as x WHERE name!="{0}" AND id IN
|
||||
(SELECT DISTINCT tag FROM books_tags_link WHERE book IN
|
||||
(SELECT DISTINCT book FROM books_tags_link WHERE tag IN
|
||||
(SELECT id FROM tags WHERE name="{0}")));
|
||||
'''.format(_('News')))
|
||||
|
||||
self.conn.executescript(u'''
|
||||
CREATE TEMP VIEW IF NOT EXISTS tag_browser_filtered_news AS SELECT DISTINCT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id and books_list_filter(book)) count
|
||||
FROM tags as x WHERE name!="{0}" AND id IN
|
||||
(SELECT DISTINCT tag FROM books_tags_link WHERE book IN
|
||||
(SELECT DISTINCT book FROM books_tags_link WHERE tag IN
|
||||
(SELECT id FROM tags WHERE name="{0}")));
|
||||
'''.format(_('News')))
|
||||
self.conn.commit()
|
||||
|
||||
|
||||
CustomColumns.__init__(self)
|
||||
template = '''\
|
||||
(SELECT {query} FROM books_{table}_link AS link INNER JOIN
|
||||
@ -576,68 +610,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
return self.conn.get('SELECT script FROM feeds WHERE id=?', (id,), all=False)
|
||||
|
||||
def get_categories(self, sort_on_count=False, ids=None, icon_map=None):
|
||||
|
||||
orig_category_columns = {'tags': ['tag', 'name'],
|
||||
'series': ['series', 'name'],
|
||||
'publishers': ['publisher', 'name'],
|
||||
'authors': ['author', 'name']} # 'news' is added below
|
||||
cat_cols = {}
|
||||
|
||||
def create_filtered_views(self, ids):
|
||||
def create_tag_browser_view(table_name, column_name, view_column_name):
|
||||
script = ('''
|
||||
CREATE TEMP VIEW IF NOT EXISTS tag_browser_filtered_{tn} AS SELECT
|
||||
id,
|
||||
{vcn},
|
||||
(SELECT COUNT(books_{tn}_link.id) FROM books_{tn}_link WHERE {cn}={tn}.id and books_list_filter(book)) count
|
||||
FROM {tn};
|
||||
'''.format(tn=table_name, cn=column_name, vcn=view_column_name))
|
||||
self.conn.executescript(script)
|
||||
|
||||
self.cat_cols = {}
|
||||
for tn,cn in orig_category_columns.iteritems():
|
||||
create_tag_browser_view(tn, cn[0], cn[1])
|
||||
cat_cols[tn] = cn
|
||||
for i,v in self.custom_column_num_map.iteritems():
|
||||
if v['datatype'] == 'text':
|
||||
tn = 'custom_column_{0}'.format(i)
|
||||
create_tag_browser_view(tn, 'value', 'value')
|
||||
cat_cols[tn] = [v['label'], 'value']
|
||||
cat_cols['news'] = ['news', 'name']
|
||||
|
||||
self.conn.executescript(u'''
|
||||
CREATE TEMP VIEW IF NOT EXISTS tag_browser_news AS SELECT DISTINCT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id) count
|
||||
FROM tags as x WHERE name!="{0}" AND id IN
|
||||
(SELECT DISTINCT tag FROM books_tags_link WHERE book IN
|
||||
(SELECT DISTINCT book FROM books_tags_link WHERE tag IN
|
||||
(SELECT id FROM tags WHERE name="{0}")));
|
||||
'''.format(_('News')))
|
||||
self.conn.commit()
|
||||
|
||||
self.conn.executescript(u'''
|
||||
CREATE TEMP VIEW IF NOT EXISTS tag_browser_filtered_news AS SELECT DISTINCT
|
||||
id,
|
||||
name,
|
||||
(SELECT COUNT(books_tags_link.id) FROM books_tags_link WHERE tag=x.id and books_list_filter(book)) count
|
||||
FROM tags as x WHERE name!="{0}" AND id IN
|
||||
(SELECT DISTINCT tag FROM books_tags_link WHERE book IN
|
||||
(SELECT DISTINCT book FROM books_tags_link WHERE tag IN
|
||||
(SELECT id FROM tags WHERE name="{0}")));
|
||||
'''.format(_('News')))
|
||||
self.conn.commit()
|
||||
|
||||
if ids is not None:
|
||||
s_ids = set(ids)
|
||||
else:
|
||||
s_ids = None
|
||||
self.conn.create_function('books_list_filter', 1, lambda(id): 1 if id in s_ids else 0)
|
||||
create_filtered_views(self, ids)
|
||||
self.books_list_filter.change([] if not ids else ids)
|
||||
|
||||
categories = {}
|
||||
for tn,cn in cat_cols.iteritems():
|
||||
for tn, cn in self.tag_browser_categories.items():
|
||||
if ids is None:
|
||||
query = 'SELECT id, {0}, count FROM tag_browser_{1}'.format(cn[1], tn)
|
||||
else:
|
||||
@ -648,12 +624,14 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
query += ' ORDER BY {0} ASC'.format(cn[1])
|
||||
data = self.conn.get(query)
|
||||
category = cn[0]
|
||||
if category in icon_map:
|
||||
icon = icon_map[category]
|
||||
tooltip = ''
|
||||
else:
|
||||
icon = icon_map['*custom']
|
||||
tooltip = self.custom_column_label_map[category]['name']
|
||||
icon, tooltip = None, ''
|
||||
if icon_map:
|
||||
if category in icon_map:
|
||||
icon = icon_map[category]
|
||||
tooltip = ''
|
||||
else:
|
||||
icon = icon_map['*custom']
|
||||
tooltip = self.custom_column_label_map[category]['name']
|
||||
if ids is None: # no filtering
|
||||
categories[category] = [Tag(r[1], count=r[2], id=r[0], icon=icon, tooltip = tooltip)
|
||||
for r in data]
|
||||
@ -666,14 +644,15 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
if ids is not None:
|
||||
count = self.conn.get('''SELECT COUNT(id)
|
||||
FROM data
|
||||
WHERE format="%s" and books_list_filter(id)'''%fmt,
|
||||
WHERE format="%s" AND books_list_filter(id)'''%fmt,
|
||||
all=False)
|
||||
else:
|
||||
count = self.conn.get('''SELECT COUNT(id)
|
||||
FROM data
|
||||
WHERE format="%s"'''%fmt,
|
||||
all=False)
|
||||
categories['format'].append(Tag(fmt, count=count))
|
||||
if count > 0:
|
||||
categories['format'].append(Tag(fmt, count=count))
|
||||
|
||||
if sort_on_count:
|
||||
categories['format'].sort(cmp=lambda x,y:cmp(x.count, y.count),
|
||||
@ -1475,6 +1454,7 @@ books_series_link feeds
|
||||
conn = ndb.conn
|
||||
conn.execute('create table temp_sequence(id INTEGER PRIMARY KEY AUTOINCREMENT)')
|
||||
conn.commit()
|
||||
conn.create_function(self.books_list_filter.name, 1, lambda x: 1)
|
||||
conn.executescript(sql)
|
||||
conn.commit()
|
||||
conn.execute('pragma user_version=%d'%user_version)
|
||||
|
@ -269,3 +269,22 @@ class SchemaUpgrade(object):
|
||||
CREATE INDEX IF NOT EXISTS formats_idx ON data (format);
|
||||
''')
|
||||
|
||||
def upgrade_version_10(self):
|
||||
'Add restricted Tag Browser views'
|
||||
def create_tag_browser_view(table_name, column_name, view_column_name):
|
||||
script = ('''
|
||||
DROP VIEW IF EXISTS tag_browser_filtered_{tn};
|
||||
CREATE VIEW tag_browser_filtered_{tn} AS SELECT
|
||||
id,
|
||||
{vcn},
|
||||
(SELECT COUNT(books_{tn}_link.id) FROM books_{tn}_link WHERE
|
||||
{cn}={tn}.id AND books_list_filter(book)) count
|
||||
FROM {tn};
|
||||
'''.format(tn=table_name, cn=column_name, vcn=view_column_name))
|
||||
self.conn.executescript(script)
|
||||
|
||||
for tn, cn in self.tag_browser_categories.items():
|
||||
if tn != 'news':
|
||||
create_tag_browser_view(tn, cn[0], cn[1])
|
||||
|
||||
|
||||
|
@ -36,6 +36,18 @@ def convert_bool(val):
|
||||
sqlite.register_adapter(bool, lambda x : 1 if x else 0)
|
||||
sqlite.register_converter('bool', convert_bool)
|
||||
|
||||
class DynamicFilter(object):
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.ids = frozenset([])
|
||||
|
||||
def __call__(self, id_):
|
||||
return int(id_ in self.ids)
|
||||
|
||||
def change(self, ids):
|
||||
self.ids = frozenset(ids)
|
||||
|
||||
|
||||
class Concatenate(object):
|
||||
'''String concatenation aggregator for sqlite'''
|
||||
@ -119,6 +131,13 @@ class DBThread(Thread):
|
||||
ok, res = True, '\n'.join(self.conn.iterdump())
|
||||
except Exception, err:
|
||||
ok, res = False, (err, traceback.format_exc())
|
||||
elif func == 'create_dynamic_filter':
|
||||
try:
|
||||
f = DynamicFilter(args[0])
|
||||
self.conn.create_function(args[0], 1, f)
|
||||
ok, res = True, f
|
||||
except Exception, err:
|
||||
ok, res = False, (err, traceback.format_exc())
|
||||
else:
|
||||
func = getattr(self.conn, func)
|
||||
try:
|
||||
@ -203,6 +222,9 @@ class ConnectionProxy(object):
|
||||
@proxy
|
||||
def dump(self): pass
|
||||
|
||||
@proxy
|
||||
def create_dynamic_filter(self): pass
|
||||
|
||||
def connect(dbpath, row_factory=None):
|
||||
conn = ConnectionProxy(DBThread(dbpath, row_factory))
|
||||
conn.proxy.start()
|
||||
|
Loading…
x
Reference in New Issue
Block a user