Source code for seriesmarker.persistence.database
#==============================================================================
# -*- coding: utf-8 -*-
#
# Copyright (C) 2013 - 2016 Tobias Röttger <toroettg@gmail.com>
#
# This file is part of SeriesMarker.
#
# SeriesMarker is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# SeriesMarker is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SeriesMarker. If not, see <http://www.gnu.org/licenses/>.
#==============================================================================
from seriesmarker.persistence.exception import EntityExistsException, \
EntityNotFoundException
from seriesmarker.util import config
from sqlalchemy.engine import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.orm.session import sessionmaker
import errno
import logging
import os
logger = logging.getLogger(__name__)
Base = declarative_base()
db_engine = None
db_session = scoped_session(sessionmaker(autoflush=False, autocommit=False))
# Imports for Metadata creation
from seriesmarker.persistence.model.banner import Banner # @UnusedImport
from seriesmarker.persistence.model.banner_extra import BannerExtra # @UnusedImport
from seriesmarker.persistence.model.role import Role # @UnusedImport
from seriesmarker.persistence.model.role_extra import RoleExtra # @UnusedImport
from seriesmarker.persistence.model.director import Director # @UnusedImport
from seriesmarker.persistence.model.writer import Writer # @UnusedImport
from seriesmarker.persistence.model.season import Season # @UnusedImport
from seriesmarker.persistence.model.guest import Guest # @UnusedImport
from seriesmarker.persistence.model.episode import Episode # @UnusedImport
from seriesmarker.persistence.model.episode_extra import EpisodeExtra # @UnusedImport
from seriesmarker.persistence.model.series_extra import SeriesExtra # @UnusedImport
from seriesmarker.persistence.model.actor import Actor # @UnusedImport
from seriesmarker.persistence.model.genre import Genre # @UnusedImport
from seriesmarker.persistence.model.series import Series
[docs]def db_init():
"""Initializes the database.
Creates or connects to a database at a location, specified by the
configuration file.
.. seealso:: :mod:`.config`
"""
global db_engine, db_session
logger.info("Initializing database '{db_name}' in '{db_location}'".format(
db_name=config.application_name,
db_location=config.dirs.user_data_dir)
)
try:
os.makedirs(config.dirs.user_data_dir)
except OSError as error:
if error.errno != errno.EEXIST:
raise
db_URL = 'sqlite:///{db_location}{sep}{db_name}.db'.format(
db_location=config.dirs.user_data_dir, sep=os.sep,
db_name=config.application_name
)
db_engine = create_engine(db_URL, echo=False)
db_session.configure(bind=db_engine)
Base.metadata.create_all(bind=db_engine)
[docs]def db_commit():
"""Writes pending changes to the database."""
db_session.commit()
[docs]def db_add_series(series):
"""Adds a new series to the database.
:param series: The series to add.
:type series: :class:`.Series`
:raises: :exc:`.EntityExistsException`
"""
try:
db_session.query(Series).filter_by(id=series.id).one()
except NoResultFound:
db_session.add(series)
db_session.commit()
logger.info("Added series '{series}'".format(series=series.series_name))
else:
raise EntityExistsException(series.id, series.__tablename__)
[docs]def db_remove_banner(banner):
"""Removes a given banner from the database.
:param banner: The banner to remove.
:type banner: :class:`.Banner`
"""
db_session.delete(banner.extra)
db_session.delete(banner)
logging.debug("Removed {banner}".format(banner=banner))
[docs]def db_remove_item(item):
"""Removes a generic (atomic) item from the database.
.. todo::
Check if item really is generic, dispatch to proper remove
function otherwise.
:param item: The item to remove.
"""
db_session.delete(item)
[docs]def db_get_series(series_id=None):
"""Queries the database for series.
:param series_id: The ID of the series to retrieve.
:type series_id: Integer or None
:returns: The :class:`.Series` related to the given ID or None
if no entry matches the ID.
:returns: An alphanumerically sorted list of all :class:`.Series`
in the database if no ID is specified (may be empty).
"""
if series_id == None:
return db_session.query(Series).order_by(Series.series_name).all()
else:
try:
return db_session.query(Series).filter_by(id=series_id).one()
except NoResultFound:
return None
[docs]def db_remove_episode(episode):
"""Removes a given episode from the database.
:param episode: The episode to remove.
:type episode: :class:`.Episode`
"""
for director in episode.directors:
db_session.delete(director)
for writer in episode.writers:
db_session.delete(writer)
for guest in episode.guests:
db_session.delete(guest)
db_session.delete(episode.extra)
db_session.delete(episode)
logging.debug("Removed {episode}".format(episode=episode))
[docs]def db_remove_season(season):
"""Removes a given season from the database.
:param season: The season to remove.
:type season: :class:`.Season`
"""
for episode in season.episodes:
db_remove_episode(episode)
if season.banner != None:
db_remove_banner(season.banner)
db_session.delete(season)
logging.debug("Removed {season}".format(season=season))
[docs]def db_remove_role(role):
"""Removes a given role from the database.
:param role: The role to remove.
:type role: :class:`.Role`
"""
db_session.delete(role.extra)
db_session.delete(role)
[docs]def db_remove_series(series):
"""Removes a given series from the database.
:param series: The series to remove.
:type series: :class:`.Series`
:raises: :exc:`.EntityNotFoundException`
"""
try:
db_session.query(Series).filter_by(id=series.id).one()
except NoResultFound:
raise EntityNotFoundException(series.id, series.__tablename__)
else:
for season in series.seasons:
db_remove_season(season)
for actor in series.actors:
db_session.delete(actor)
for genre in series.genre:
db_session.delete(genre)
for role in series.extra.roles:
db_session.delete(role.extra)
db_session.delete(role)
if series.extra.banner != None:
db_remove_banner(series.extra.banner)
db_session.delete(series.extra)
db_session.delete(series)
db_session.commit()
logging.info("Removed series '{series}'".format(
series=series.series_name)
)