Make associated_directory its own table so albums can have multiple

Also renamed a bunch of indices
This commit is contained in:
voussoir 2017-03-16 23:57:31 -07:00
parent 440941077f
commit efa930f4a8
4 changed files with 137 additions and 73 deletions

View file

@ -31,11 +31,14 @@ SQL_LASTID_COLUMNS = [
'table',
'last_id',
]
SQL_ALBUM_DIRECTORY_COLUMNS = [
'albumid',
'directory',
]
SQL_ALBUM_COLUMNS = [
'id',
'title',
'description',
'associated_directory',
]
SQL_BOOKMARK_COLUMNS = [
'id',
@ -92,6 +95,7 @@ SQL_USER_COLUMNS = [
_sql_dictify = lambda columns: {key:index for (index, key) in enumerate(columns)}
SQL_ALBUM = _sql_dictify(SQL_ALBUM_COLUMNS)
SQL_ALBUM_DIRECTORY = _sql_dictify(SQL_ALBUM_DIRECTORY_COLUMNS)
SQL_ALBUMGROUP = _sql_dictify(SQL_ALBUMGROUP_COLUMNS)
SQL_BOOKMARK = _sql_dictify(SQL_BOOKMARK_COLUMNS)
SQL_ALBUMPHOTO = _sql_dictify(SQL_ALBUMPHOTO_COLUMNS)

View file

@ -54,6 +54,13 @@ class NoSuchUser(NoSuch):
# EXISTS
@with_error_type
class AlbumExists(WithFormat):
error_message = 'Album "{}" already exists.'
def __init__(self, album):
self.album = album
WithFormat.__init__(self, album.id)
@with_error_type
class GroupExists(WithFormat):
error_message = '{member} already in group {group}'

View file

@ -29,23 +29,64 @@ logging.getLogger('PIL.PngImagePlugin').setLevel(logging.WARNING)
# Note: Setting user_version pragma in init sequence is safe because it only
# happens after the out-of-date check occurs, so no chance of accidentally
# overwriting it.
DATABASE_VERSION = 6
DATABASE_VERSION = 7
DB_INIT = '''
PRAGMA count_changes = OFF;
PRAGMA cache_size = 10000;
PRAGMA user_version = {user_version};
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS album_associated_directories(
albumid TEXT,
directory TEXT COLLATE NOCASE
);
CREATE INDEX IF NOT EXISTS index_album_associated_directories_albumid on
album_associated_directories(albumid);
CREATE INDEX IF NOT EXISTS index_album_associated_directories_directory on
album_associated_directories(directory);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS album_group_rel(
parentid TEXT,
memberid TEXT
);
CREATE INDEX IF NOT EXISTS index_album_group_rel_parentid on album_group_rel(parentid);
CREATE INDEX IF NOT EXISTS index_album_group_rel_memberid on album_group_rel(memberid);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS album_photo_rel(
albumid TEXT,
photoid TEXT
);
CREATE INDEX IF NOT EXISTS index_album_photo_rel_albumid on album_photo_rel(albumid);
CREATE INDEX IF NOT EXISTS index_album_photo_rel_photoid on album_photo_rel(photoid);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS albums(
id TEXT,
title TEXT,
description TEXT,
associated_directory TEXT COLLATE NOCASE
description TEXT
);
CREATE INDEX IF NOT EXISTS index_albums_id on albums(id);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS bookmarks(
id TEXT,
title TEXT,
url TEXT,
author_id TEXT
);
CREATE INDEX IF NOT EXISTS index_bookmarks_id on bookmarks(id);
CREATE INDEX IF NOT EXISTS index_bookmarks_author on bookmarks(author_id);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS id_numbers(
tab TEXT,
last_id TEXT
);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS photo_tag_rel(
photoid TEXT,
tagid TEXT
);
CREATE INDEX IF NOT EXISTS index_photo_tag_rel_photoid on photo_tag_rel(photoid);
CREATE INDEX IF NOT EXISTS index_photo_tag_rel_tagid on photo_tag_rel(tagid);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS photos(
id TEXT,
filepath TEXT COLLATE NOCASE,
@ -62,82 +103,42 @@ CREATE TABLE IF NOT EXISTS photos(
tagged_at INT,
author_id TEXT
);
CREATE TABLE IF NOT EXISTS tags(
id TEXT,
name TEXT
);
CREATE TABLE IF NOT EXISTS album_photo_rel(
albumid TEXT,
photoid TEXT
);
CREATE TABLE IF NOT EXISTS album_group_rel(
parentid TEXT,
memberid TEXT
);
CREATE TABLE IF NOT EXISTS photo_tag_rel(
photoid TEXT,
tagid TEXT
);
CREATE INDEX IF NOT EXISTS index_photos_id on photos(id);
CREATE INDEX IF NOT EXISTS index_photos_filepath on photos(filepath COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS index_photos_override_filename on
photos(override_filename COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS index_photos_created on photos(created);
CREATE INDEX IF NOT EXISTS index_photos_extension on photos(extension);
CREATE INDEX IF NOT EXISTS index_photos_author_id on photos(author_id);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS tag_group_rel(
parentid TEXT,
memberid TEXT
);
CREATE INDEX IF NOT EXISTS index_tag_group_rel_parentid on tag_group_rel(parentid);
CREATE INDEX IF NOT EXISTS index_tag_group_rel_memberid on tag_group_rel(memberid);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS tag_synonyms(
name TEXT,
mastername TEXT
);
CREATE TABLE IF NOT EXISTS id_numbers(
tab TEXT,
last_id TEXT
CREATE INDEX IF NOT EXISTS index_tag_synonyms_name on tag_synonyms(name);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS tags(
id TEXT,
name TEXT
);
CREATE INDEX IF NOT EXISTS index_tags_id on tags(id);
CREATE INDEX IF NOT EXISTS index_tags_name on tags(name);
----------------------------------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS users(
id TEXT,
username TEXT COLLATE NOCASE,
password BLOB,
created INT
);
-- Album
CREATE INDEX IF NOT EXISTS index_album_id on albums(id);
-- Album-photo relation
CREATE INDEX IF NOT EXISTS index_albumrel_albumid on album_photo_rel(albumid);
CREATE INDEX IF NOT EXISTS index_albumrel_photoid on album_photo_rel(photoid);
-- Album-group relation
CREATE INDEX IF NOT EXISTS index_albumgroup_parentid on album_group_rel(parentid);
CREATE INDEX IF NOT EXISTS index_albumgroup_memberid on album_group_rel(memberid);
-- Bookmark
CREATE INDEX IF NOT EXISTS index_bookmark_id on bookmarks(id);
CREATE INDEX IF NOT EXISTS index_bookmark_author on bookmarks(author_id);
-- Photo
CREATE INDEX IF NOT EXISTS index_photo_id on photos(id);
CREATE INDEX IF NOT EXISTS index_photo_path on photos(filepath COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS index_photo_fakepath on photos(override_filename COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS index_photo_created on photos(created);
CREATE INDEX IF NOT EXISTS index_photo_extension on photos(extension);
CREATE INDEX IF NOT EXISTS index_photo_author on photos(author_id);
-- Tag
CREATE INDEX IF NOT EXISTS index_tag_id on tags(id);
CREATE INDEX IF NOT EXISTS index_tag_name on tags(name);
-- Photo-tag relation
CREATE INDEX IF NOT EXISTS index_tagrel_photoid on photo_tag_rel(photoid);
CREATE INDEX IF NOT EXISTS index_tagrel_tagid on photo_tag_rel(tagid);
-- Tag-synonym relation
CREATE INDEX IF NOT EXISTS index_tagsyn_name on tag_synonyms(name);
-- Tag-group relation
CREATE INDEX IF NOT EXISTS index_taggroup_parentid on tag_group_rel(parentid);
CREATE INDEX IF NOT EXISTS index_taggroup_memberid on tag_group_rel(memberid);
-- User
CREATE INDEX IF NOT EXISTS index_user_id on users(id);
CREATE INDEX IF NOT EXISTS index_user_username on users(username COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS index_users_id on users(id);
CREATE INDEX IF NOT EXISTS index_users_username on users(username COLLATE NOCASE);
'''.format(user_version=DATABASE_VERSION)
@ -260,11 +261,12 @@ class PDBAlbumMixin:
'''
filepath = os.path.abspath(filepath)
cur = self.sql.cursor()
cur.execute('SELECT * FROM albums WHERE associated_directory == ?', [filepath])
cur.execute('SELECT * FROM album_associated_directories WHERE directory == ?', [filepath])
fetch = cur.fetchone()
if fetch is None:
raise exceptions.NoSuchAlbum(filepath)
return self.get_album(fetch[constants.SQL_ALBUM['id']])
album_id = fetch[constants.SQL_ALBUM_DIRECTORY['albumid']]
return self.get_album(album_id)
def get_albums(self):
yield from self.get_things(thing_type='album')
@ -287,29 +289,45 @@ class PDBAlbumMixin:
albumid = self.generate_id('albums')
title = title or ''
description = description or ''
if associated_directory is not None:
associated_directory = os.path.abspath(associated_directory)
if not isinstance(title, str):
raise TypeError('Title must be string, not %s' % type(title))
if not isinstance(description, str):
raise TypeError('Description must be string, not %s' % type(description))
cur = self.sql.cursor()
if associated_directory is not None:
associated_directory = os.path.abspath(associated_directory)
cur.execute(
'SELECT * FROM album_associated_directories WHERE directory == ?',
[associated_directory]
)
fetch = cur.fetchone()
if fetch is not None:
album = self.get_album(fetch[constants.SQL_ALBUM_DIRECTORY['albumid']])
raise exceptions.AlbumExists(album)
self.log.debug('New Album: %s' % title)
data = {
'id': albumid,
'title': title,
'description': description,
'associated_directory': associated_directory,
}
(qmarks, bindings) = helpers.binding_filler(constants.SQL_ALBUM_COLUMNS, data)
query = 'INSERT INTO albums VALUES(%s)' % qmarks
cur = self.sql.cursor()
cur.execute(query, bindings)
album = objects.Album(self, data)
if associated_directory is not None:
data = {
'albumid': albumid,
'directory': associated_directory,
}
(qmarks, bindings) = helpers.binding_filler(constants.SQL_ALBUM_DIRECTORY_COLUMNS, data)
query = 'INSERT INTO album_associated_directories VALUES(%s)' % qmarks
cur.execute(query, bindings)
if photos:
for photo in photos:
photo = self.get_photo(photo)

View file

@ -103,6 +103,41 @@ def upgrade_5_to_6(sql):
[album_id, album_id]
)
def upgrade_6_to_7(sql):
'''
Most of the indices were renamed, so delete them and let them regenerate
next time.
Albums lost their `associated_directory` column, and it has been moved to a
separate table `album_associated_directories`, so that we can have albums
which load from multiple directories.
'''
cur = sql.cursor()
cur.execute('SELECT name FROM sqlite_master WHERE type == "index"')
indices = [x[0] for x in cur.fetchall()]
for index in indices:
cur.execute('DROP INDEX %s' % index)
cur.execute('''
CREATE TABLE album_associated_directories(
albumid TEXT,
directory TEXT COLLATE NOCASE
)''')
cur.execute('ALTER TABLE albums RENAME TO deleting_albums')
cur.execute('''
CREATE TABLE albums(
id TEXT,
title TEXT,
description TEXT
)''')
cur.execute('INSERT INTO albums SELECT id, title, description FROM deleting_albums')
cur.execute('''
INSERT INTO album_associated_directories SELECT id, associated_directory FROM deleting_albums
''')
cur.execute('DROP TABLE deleting_albums')
def upgrade_all(database_filename):
'''
Given the filename of a phototagger database, apply all of the needed