From 9ea6e0d2a94261619ec65b4b2faf8392937fa32a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 13 Jul 2013 10:03:31 +0530 Subject: [PATCH] conversion_options API --- src/calibre/db/backend.py | 24 +++++++++++++++++++++++- src/calibre/db/cache.py | 16 ++++++++++++++++ src/calibre/db/legacy.py | 12 ++++++++++++ src/calibre/db/tests/legacy.py | 24 +++++++++++++++++++++++- src/calibre/db/tests/writing.py | 17 +++++++++++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/calibre/db/backend.py b/src/calibre/db/backend.py index 8ebdc4a154..0ebc9679b7 100644 --- a/src/calibre/db/backend.py +++ b/src/calibre/db/backend.py @@ -8,7 +8,7 @@ __copyright__ = '2011, Kovid Goyal ' __docformat__ = 'restructuredtext en' # Imports {{{ -import os, shutil, uuid, json, glob, time +import os, shutil, uuid, json, glob, time, cPickle from functools import partial import apsw @@ -1216,5 +1216,27 @@ class DB(object): def get_ids_for_custom_book_data(self, name): return frozenset(r[0] for r in self.conn.execute('SELECT book FROM books_plugin_data WHERE name=?', (name,))) + def conversion_options(self, book_id, fmt): + for (data,) in self.conn.get('SELECT data FROM conversion_options WHERE book=? AND format=?', (book_id, fmt.upper())): + if data: + return cPickle.loads(bytes(data)) + + def has_conversion_options(self, ids, fmt='PIPE'): + ids = frozenset(ids) + self.conn.execute('DROP TABLE IF EXISTS conversion_options_temp; CREATE TEMP TABLE conversion_options_temp (id INTEGER PRIMARY KEY);') + self.conn.executemany('INSERT INTO conversion_options_temp VALUES (?)', [(x,) for x in ids]) + for (book_id,) in self.conn.get( + 'SELECT book FROM conversion_options WHERE format=? AND book IN (SELECT id FROM conversion_options_temp)', (fmt.upper(),)): + return True + return False + + def delete_conversion_options(self, book_ids, fmt): + self.conn.executemany('DELETE FROM conversion_options WHERE book=? AND format=?', + [(book_id, fmt.upper()) for book_id in book_ids]) + + def set_conversion_options(self, options, fmt): + options = [(book_id, fmt.upper(), buffer(cPickle.dumps(data, -1))) for book_id, data in options.iteritems()] + self.conn.executemany('INSERT OR REPLACE INTO conversion_options(book,format,data) VALUES (?,?,?)', options) + # }}} diff --git a/src/calibre/db/cache.py b/src/calibre/db/cache.py index bc8f1024f5..a36e53c175 100644 --- a/src/calibre/db/cache.py +++ b/src/calibre/db/cache.py @@ -1208,6 +1208,22 @@ class Cache(object): ''' Return the set of book ids for which name has data. ''' return self.backend.get_ids_for_custom_book_data(name) + @read_api + def conversion_options(self, book_id, fmt='PIPE'): + return self.backend.conversion_options(book_id, fmt) + + @read_api + def has_conversion_options(self, ids, fmt='PIPE'): + return self.backend.has_conversion_options(ids, fmt) + + @write_api + def delete_conversion_options(self, book_ids, fmt='PIPE'): + return self.backend.delete_conversion_options(book_ids, fmt) + + @write_api + def set_conversion_options(self, options, fmt='PIPE'): + ''' options must be a map of the form {book_id:conversion_options} ''' + return self.backend.set_conversion_options(options, fmt) # }}} diff --git a/src/calibre/db/legacy.py b/src/calibre/db/legacy.py index 8c5fa5bd31..03146ea1dc 100644 --- a/src/calibre/db/legacy.py +++ b/src/calibre/db/legacy.py @@ -383,6 +383,18 @@ class LibraryDatabase(object): break return ans + def set_conversion_options(self, book_id, fmt, options): + self.new_api.set_conversion_options({book_id:options}, fmt=fmt) + + def conversion_options(self, book_id, fmt): + return self.new_api.conversion_options(book_id, fmt=fmt) + + def has_conversion_options(self, ids, format='PIPE'): + return self.new_api.has_conversion_options(ids, fmt=format) + + def delete_conversion_options(self, book_id, fmt, commit=True): + self.new_api.delete_conversion_options((book_id,), fmt=fmt) + # Private interface {{{ def __iter__(self): for row in self.data.iterall(): diff --git a/src/calibre/db/tests/legacy.py b/src/calibre/db/tests/legacy.py index eabd351bde..bda3401107 100644 --- a/src/calibre/db/tests/legacy.py +++ b/src/calibre/db/tests/legacy.py @@ -191,6 +191,27 @@ class LegacyTest(BaseTest): db.close() # }}} + def test_legacy_conversion_options(self): # {{{ + 'Test conversion options API' + ndb = self.init_legacy() + db = self.init_old() + all_ids = ndb.new_api.all_book_ids() + op1, op2 = {'xx':'yy'}, {'yy':'zz'} + for x in ( + ('has_conversion_options', all_ids), + ('conversion_options', 1, 'PIPE'), + ('set_conversion_options', 1, 'PIPE', op1), + ('has_conversion_options', all_ids), + ('conversion_options', 1, 'PIPE'), + ('delete_conversion_options', 1, 'PIPE'), + ('has_conversion_options', all_ids), + ): + meth, args = x[0], x[1:] + self.assertEqual((getattr(db, meth)(*args)), (getattr(ndb, meth)(*args)), + 'The method: %s() returned different results for argument %s' % (meth, args)) + db.close() + # }}} + def test_legacy_adding_books(self): # {{{ 'Test various adding books methods' from calibre.ebooks.metadata.book.base import Metadata @@ -271,7 +292,8 @@ class LegacyTest(BaseTest): # Internal API 'clean_user_categories', 'cleanup_tags', 'books_list_filter', 'conn', 'connect', 'construct_file_name', 'construct_path_name', 'clear_dirtied', 'commit_dirty_cache', 'initialize_database', 'initialize_dynamic', - 'run_import_plugins', + 'run_import_plugins', 'vacuum', 'set_path', 'row', 'row_factory', 'rows', 'rmtree', 'series_index_pat', + 'import_old_database', 'dirtied_lock', 'dirtied_cache', 'dirty_queue_length', } SKIP_ARGSPEC = { '__init__', 'get_next_series_num_for', 'has_book', 'author_sort_from_authors', diff --git a/src/calibre/db/tests/writing.py b/src/calibre/db/tests/writing.py index cb525900ee..36b6d3d2a3 100644 --- a/src/calibre/db/tests/writing.py +++ b/src/calibre/db/tests/writing.py @@ -419,3 +419,20 @@ class WritingTest(BaseTest): # }}} + def test_conversion_options(self): # {{{ + ' Test saving of conversion options ' + cache = self.init_cache() + all_ids = cache.all_book_ids() + self.assertFalse(cache.has_conversion_options(all_ids)) + self.assertIsNone(cache.conversion_options(1)) + op1, op2 = {'xx':'yy'}, {'yy':'zz'} + cache.set_conversion_options({1:op1, 2:op2}) + self.assertTrue(cache.has_conversion_options(all_ids)) + self.assertEqual(cache.conversion_options(1), op1) + self.assertEqual(cache.conversion_options(2), op2) + cache.set_conversion_options({1:op2}) + self.assertEqual(cache.conversion_options(1), op2) + cache.delete_conversion_options(all_ids) + self.assertFalse(cache.has_conversion_options(all_ids)) + # }}} +