mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
...
This commit is contained in:
parent
9d041c7969
commit
c51a171384
@ -7,9 +7,33 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from functools import wraps
|
||||
|
||||
from calibre.db.locking import create_locks
|
||||
from calibre.db.fields import create_field
|
||||
|
||||
def api(f):
|
||||
f.is_cache_api = True
|
||||
return f
|
||||
|
||||
def read_api(f):
|
||||
f = api(f)
|
||||
f.is_read_api = True
|
||||
return f
|
||||
|
||||
def write_api(f):
|
||||
f = api(f)
|
||||
f.is_read_api = False
|
||||
return f
|
||||
|
||||
def wrap_simple(lock, func):
|
||||
@wraps(func)
|
||||
def ans(*args, **kwargs):
|
||||
with lock:
|
||||
return func(*args, **kwargs)
|
||||
return ans
|
||||
|
||||
|
||||
class Cache(object):
|
||||
|
||||
def __init__(self, backend):
|
||||
@ -17,14 +41,100 @@ class Cache(object):
|
||||
self.fields = {}
|
||||
self.read_lock, self.write_lock = create_locks()
|
||||
|
||||
# Implement locking for all simple read/write API methods
|
||||
# An unlocked version of the method is stored with the name starting
|
||||
# with a leading underscore. Use the unlocked versions when the lock
|
||||
# has already been acquired.
|
||||
for name in dir(self):
|
||||
func = getattr(self, name)
|
||||
ira = getattr(func, 'is_read_api', None)
|
||||
if ira is not None:
|
||||
# Save original function
|
||||
setattr(self, '_'+name, func)
|
||||
# Wrap it in a lock
|
||||
lock = self.read_lock if ira else self.write_lock
|
||||
setattr(self, name, wrap_simple(lock, func))
|
||||
|
||||
# Cache Layer API {{{
|
||||
|
||||
@api
|
||||
def init(self):
|
||||
'''
|
||||
Initialize this cache with data from the backend.
|
||||
'''
|
||||
with self.write_lock:
|
||||
self.backend.read_tables()
|
||||
|
||||
for field, table in self.backend.tables.iteritems():
|
||||
self.fields[field] = create_field(field, table)
|
||||
|
||||
@read_api
|
||||
def field_for(self, name, book_id, default_value=None):
|
||||
'''
|
||||
Return the value of the field ``name`` for the book identified by
|
||||
``book_id``. If no such book exists or it has no defined value for the
|
||||
field ``name`` or no such field exists, then ``default_value`` is returned.
|
||||
|
||||
The returned value for is_multiple fields are always tuples.
|
||||
'''
|
||||
try:
|
||||
return self.fields[name].for_book(book_id, default_value=default_value)
|
||||
except (KeyError, IndexError):
|
||||
return default_value
|
||||
|
||||
@read_api
|
||||
def field_ids_for(self, name, book_id):
|
||||
'''
|
||||
Return the ids (as a tuple) for the values that the field ``name`` has on the book
|
||||
identified by ``book_id``. If there are no values, or no such book, or
|
||||
no such field, an empty tuple is returned.
|
||||
'''
|
||||
try:
|
||||
return self.fields[name].ids_for_book(book_id)
|
||||
except (KeyError, IndexError):
|
||||
return ()
|
||||
|
||||
@read_api
|
||||
def books_for_field(self, name, item_id):
|
||||
'''
|
||||
Return all the books associated with the item identified by
|
||||
``item_id``, where the item belongs to the field ``name``.
|
||||
|
||||
Returned value is a tuple of book ids, or the empty tuple if the item
|
||||
or the field does not exist.
|
||||
'''
|
||||
try:
|
||||
return self.fields[name].books_for(item_id)
|
||||
except (KeyError, IndexError):
|
||||
return ()
|
||||
|
||||
@read_api
|
||||
def all_book_ids(self):
|
||||
'''
|
||||
Frozen set of all known book ids.
|
||||
'''
|
||||
return frozenset(self.fields['uuid'].iter_book_ids())
|
||||
|
||||
@read_api
|
||||
def all_field_ids(self, name):
|
||||
'''
|
||||
Frozen set of ids for all values in the field ``name``.
|
||||
'''
|
||||
return frozenset(iter(self.fields[name]))
|
||||
|
||||
# }}}
|
||||
|
||||
# Testing {{{
|
||||
|
||||
def test(library_path):
|
||||
from calibre.db.backend import DB
|
||||
backend = DB(library_path)
|
||||
cache = Cache(backend)
|
||||
cache.init()
|
||||
print ('All book ids:', cache.all_book_ids())
|
||||
|
||||
if __name__ == '__main__':
|
||||
from calibre.utils.config import prefs
|
||||
test(prefs['library_path'])
|
||||
|
||||
# }}}
|
||||
|
@ -63,6 +63,9 @@ class OneToOneField(Field):
|
||||
def __iter__(self):
|
||||
return self.table.book_col_map.iterkeys()
|
||||
|
||||
def iter_book_ids(self):
|
||||
return self.table.book_col_map.iterkeys()
|
||||
|
||||
class ManyToOneField(Field):
|
||||
|
||||
def for_book(self, book_id, default_value=None):
|
||||
|
@ -110,8 +110,8 @@ class ManyToOneTable(Table):
|
||||
self.col_book_map[row[1]].append(row[0])
|
||||
self.book_col_map[row[0]] = row[1]
|
||||
|
||||
for key, val in self.col_book_map:
|
||||
self.col_book_map[key] = tuple(val)
|
||||
for key in tuple(self.col_book_map.iterkeys()):
|
||||
self.col_book_map[key] = tuple(self.col_book_map[key])
|
||||
|
||||
class ManyToManyTable(ManyToOneTable):
|
||||
|
||||
@ -134,20 +134,21 @@ class ManyToManyTable(ManyToOneTable):
|
||||
self.book_col_map[row[0]] = []
|
||||
self.book_col_map[row[0]].append(row[1])
|
||||
|
||||
for key, val in self.col_book_map:
|
||||
self.col_book_map[key] = tuple(val)
|
||||
for key in tuple(self.col_book_map.iterkeys()):
|
||||
self.col_book_map[key] = tuple(self.col_book_map[key])
|
||||
|
||||
for key, val in self.book_col_map:
|
||||
self.book_col_map[key] = tuple(val)
|
||||
for key in tuple(self.book_col_map.iterkeys()):
|
||||
self.book_col_map[key] = tuple(self.book_col_map[key])
|
||||
|
||||
class AuthorsTable(ManyToManyTable):
|
||||
|
||||
def read_id_maps(self, db):
|
||||
self.alink_map = {}
|
||||
self.sort_map = {}
|
||||
for row in db.conn.execute(
|
||||
'SELECT id, name, sort, link FROM authors'):
|
||||
self.id_map[row[0]] = row[1]
|
||||
self.extra_map[row[0]] = (row[2] if row[2] else
|
||||
self.sort_map[row[0]] = (row[2] if row[2] else
|
||||
author_to_author_sort(row[1]))
|
||||
self.alink_map[row[0]] = row[3]
|
||||
|
||||
@ -166,11 +167,11 @@ class FormatsTable(ManyToManyTable):
|
||||
self.book_col_map[row[0]] = []
|
||||
self.book_col_map[row[0]].append((row[1], row[2]))
|
||||
|
||||
for key, val in self.col_book_map:
|
||||
self.col_book_map[key] = tuple(val)
|
||||
for key in tuple(self.col_book_map.iterkeys()):
|
||||
self.col_book_map[key] = tuple(self.col_book_map[key])
|
||||
|
||||
for key, val in self.book_col_map:
|
||||
self.book_col_map[key] = tuple(val)
|
||||
for key in tuple(self.book_col_map.iterkeys()):
|
||||
self.book_col_map[key] = tuple(self.book_col_map[key])
|
||||
|
||||
class IdentifiersTable(ManyToManyTable):
|
||||
|
||||
@ -187,9 +188,9 @@ class IdentifiersTable(ManyToManyTable):
|
||||
self.book_col_map[row[0]] = []
|
||||
self.book_col_map[row[0]].append((row[1], row[2]))
|
||||
|
||||
for key, val in self.col_book_map:
|
||||
self.col_book_map[key] = tuple(val)
|
||||
for key in tuple(self.col_book_map.iterkeys()):
|
||||
self.col_book_map[key] = tuple(self.col_book_map[key])
|
||||
|
||||
for key, val in self.book_col_map:
|
||||
self.book_col_map[key] = tuple(val)
|
||||
for key in tuple(self.book_col_map.iterkeys()):
|
||||
self.book_col_map[key] = tuple(self.book_col_map[key])
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user