1
0
mirror of https://github.com/janeczku/calibre-web synced 2024-11-24 18:47:23 +00:00

Initial attempt at setting up CalibreDB as a class that carries the engine and DB connection, and the instance being the session

This commit is contained in:
blitzmann 2020-09-11 22:52:40 -04:00
parent 7929711fea
commit 18d16f9a8b
2 changed files with 91 additions and 66 deletions

View File

@ -83,6 +83,8 @@ log = logger.create()
from . import services from . import services
db.CalibreDB.setup_db(config, cli.settingspath)
calibre_db = db.CalibreDB() calibre_db = db.CalibreDB()
def create_app(): def create_app():
@ -101,7 +103,6 @@ def create_app():
app.secret_key = os.getenv('SECRET_KEY', config_sql.get_flask_session_key(ub.session)) app.secret_key = os.getenv('SECRET_KEY', config_sql.get_flask_session_key(ub.session))
web_server.init_app(app, config) web_server.init_app(app, config)
calibre_db.setup_db(config, cli.settingspath)
babel.init_app(app) babel.init_app(app)
_BABEL_TRANSLATIONS.update(str(item) for item in babel.list_translations()) _BABEL_TRANSLATIONS.update(str(item) for item in babel.list_translations())

View File

@ -42,8 +42,11 @@ from flask_babel import gettext as _
from . import logger, ub, isoLanguages from . import logger, ub, isoLanguages
from .pagination import Pagination from .pagination import Pagination
from weakref import WeakSet
try: try:
import unidecode import unidecode
use_unidecode = True use_unidecode = True
except ImportError: except ImportError:
use_unidecode = False use_unidecode = False
@ -354,6 +357,7 @@ class Books(Base):
def atom_timestamp(self): def atom_timestamp(self):
return (self.timestamp.strftime('%Y-%m-%dT%H:%M:%S+00:00') or '') return (self.timestamp.strftime('%Y-%m-%dT%H:%M:%S+00:00') or '')
class Custom_Columns(Base): class Custom_Columns(Base):
__tablename__ = 'custom_columns' __tablename__ = 'custom_columns'
@ -373,6 +377,7 @@ class Custom_Columns(Base):
display_dict['enum_values'] = [x.decode('unicode_escape') for x in display_dict['enum_values']] display_dict['enum_values'] = [x.decode('unicode_escape') for x in display_dict['enum_values']]
return display_dict return display_dict
class AlchemyEncoder(json.JSONEncoder): class AlchemyEncoder(json.JSONEncoder):
def default(self, obj): def default(self, obj):
@ -408,16 +413,28 @@ class AlchemyEncoder(json.JSONEncoder):
class CalibreDB(): class CalibreDB():
_init = False
engine = None
log = None # todo: ??? this isn't used, and even then, not sure if it's supposed to be per session or what
config = None
session_factory = None
instances = WeakSet()
def __init__(self): def __init__(self):
self.engine = None """ Initialize a new CalibreDB session
self.session = None """
self.log = None if not self._init:
self.config = None raise Exception("CalibreDB not initialized")
self.session = self.session_factory()
self.instances.add(self)
self.update_title_sort(self.config)
def setup_db(self, config, app_db_path): @classmethod
self.config = config def setup_db(cls, config, app_db_path):
self.dispose() cls.config = config
cls.dispose()
# todo: remove...?
global Session global Session
if not config.config_calibre_dir: if not config.config_calibre_dir:
@ -430,22 +447,21 @@ class CalibreDB():
return False return False
try: try:
self.engine = create_engine('sqlite://', cls.engine = create_engine('sqlite://',
echo=False, echo=False,
isolation_level="SERIALIZABLE", isolation_level="SERIALIZABLE",
connect_args={'check_same_thread': False}, connect_args={'check_same_thread': False},
poolclass=StaticPool) poolclass=StaticPool)
self.engine.execute("attach database '{}' as calibre;".format(dbpath)) cls.engine.execute("attach database '{}' as calibre;".format(dbpath))
self.engine.execute("attach database '{}' as app_settings;".format(app_db_path)) cls.engine.execute("attach database '{}' as app_settings;".format(app_db_path))
conn = self.engine.connect() conn = cls.engine.connect()
# conn.text_factory = lambda b: b.decode(errors = 'ignore') possible fix for #1302 # conn.text_factory = lambda b: b.decode(errors = 'ignore') possible fix for #1302
except Exception as e: except Exception as e:
config.invalidate(e) config.invalidate(e)
return False return False
config.db_configured = True config.db_configured = True
self.update_title_sort(config, conn.connection)
if not cc_classes: if not cc_classes:
cc = conn.execute("SELECT id, datatype FROM custom_columns") cc = conn.execute("SELECT id, datatype FROM custom_columns")
@ -515,10 +531,10 @@ class CalibreDB():
secondary=books_custom_column_links[cc_id[0]], secondary=books_custom_column_links[cc_id[0]],
backref='books')) backref='books'))
Session = scoped_session(sessionmaker(autocommit=False, cls.session_factory = scoped_session(sessionmaker(autocommit=False,
autoflush=True, autoflush=True,
bind=self.engine)) bind=cls.engine))
self.session = Session() cls._init = True
return True return True
def get_book(self, book_id): def get_book(self, book_id):
@ -575,7 +591,8 @@ class CalibreDB():
def fill_indexpage(self, page, pagesize, database, db_filter, order, *join): def fill_indexpage(self, page, pagesize, database, db_filter, order, *join):
return self.fill_indexpage_with_archived_books(page, pagesize, database, db_filter, order, False, *join) return self.fill_indexpage_with_archived_books(page, pagesize, database, db_filter, order, False, *join)
def fill_indexpage_with_archived_books(self, page, pagesize, database, db_filter, order, allow_show_archived, *join): def fill_indexpage_with_archived_books(self, page, pagesize, database, db_filter, order, allow_show_archived,
*join):
pagesize = pagesize or self.config.config_books_per_page pagesize = pagesize or self.config.config_books_per_page
if current_user.show_detail_random(): if current_user.show_detail_random():
randm = self.session.query(Books) \ randm = self.session.query(Books) \
@ -687,17 +704,23 @@ class CalibreDB():
conn = conn or self.session.connection().connection.connection conn = conn or self.session.connection().connection.connection
conn.create_function("title_sort", 1, _title_sort) conn.create_function("title_sort", 1, _title_sort)
def dispose(self): @classmethod
def dispose(cls):
# global session # global session
old_session = self.session for inst in cls.instances:
self.session = None old_session = inst.session
inst.session = None
if old_session: if old_session:
try: old_session.close() try:
except: pass old_session.close()
except:
pass
if old_session.bind: if old_session.bind:
try: old_session.bind.dispose() try:
except Exception: pass old_session.bind.dispose()
except Exception:
pass
for attr in list(Books.__dict__.keys()): for attr in list(Books.__dict__.keys()):
if attr.startswith("custom_column_"): if attr.startswith("custom_column_"):
@ -714,10 +737,11 @@ class CalibreDB():
Base.metadata.remove(table) Base.metadata.remove(table)
def reconnect_db(self, config, app_db_path): def reconnect_db(self, config, app_db_path):
self.session.close() self.dispose()
self.engine.dispose() self.engine.dispose()
self.setup_db(config, app_db_path) self.setup_db(config, app_db_path)
def lcase(s): def lcase(s):
try: try:
return unidecode.unidecode(s.lower()) return unidecode.unidecode(s.lower())