2016-11-29 04:18:44 +00:00
|
|
|
import argparse
|
2020-12-30 23:28:52 +00:00
|
|
|
import os
|
2022-10-29 20:55:35 +00:00
|
|
|
import shutil
|
2016-11-29 04:18:44 +00:00
|
|
|
import sys
|
|
|
|
|
2022-10-29 20:55:35 +00:00
|
|
|
from voussoirkit import gentools
|
2022-07-16 06:00:07 +00:00
|
|
|
from voussoirkit import vlogging
|
|
|
|
|
2018-03-10 01:10:27 +00:00
|
|
|
import etiquette
|
2016-11-29 04:18:44 +00:00
|
|
|
|
2022-07-16 06:00:07 +00:00
|
|
|
log = vlogging.get_logger(__name__, 'database_upgrader')
|
|
|
|
|
2021-01-02 21:51:53 +00:00
|
|
|
class Migrator:
|
2020-12-30 23:19:48 +00:00
|
|
|
'''
|
|
|
|
Many of the upgraders involve adding columns. ALTER TABLE ADD COLUMN only
|
|
|
|
allows adding at the end, which I usually don't prefer. In order to add a
|
|
|
|
column in the middle, you must rename the table, create a new one, transfer
|
|
|
|
the data, and drop the old one. But, foreign keys and indices will still
|
|
|
|
point to the old table, which causes broken foreign keys and dropped
|
|
|
|
indices. So, the only way to prevent all that is to regenerate all affected
|
2021-01-02 21:51:53 +00:00
|
|
|
tables and indices. Rather than parsing relationships to determine the
|
2020-12-30 23:19:48 +00:00
|
|
|
affected tables, this implementation just regenerates everything.
|
|
|
|
|
|
|
|
It's kind of horrible but it allows me to have the columns in the order I
|
|
|
|
want instead of just always appending. Besides, modifying collations cannot
|
|
|
|
be done in-place either.
|
2021-01-02 21:51:53 +00:00
|
|
|
|
|
|
|
If you want to truly remove a table or index and not have it get
|
|
|
|
regenerated, just do that before instantiating the Migrator.
|
2020-12-30 23:19:48 +00:00
|
|
|
'''
|
2021-01-02 21:51:53 +00:00
|
|
|
def __init__(self, photodb):
|
2020-12-30 23:19:48 +00:00
|
|
|
self.photodb = photodb
|
|
|
|
|
2022-10-29 21:11:29 +00:00
|
|
|
query = 'SELECT name FROM sqlite_master WHERE type == "table"'
|
|
|
|
table_names = list(self.photodb.select(query))
|
|
|
|
self.tables = {name: {} for name in table_names}
|
2021-01-02 21:51:53 +00:00
|
|
|
|
|
|
|
# The user may be adding entirely new tables derived from the data of
|
|
|
|
# old ones. We'll need to skip new tables for the rename and drop_old
|
|
|
|
# steps. So we track which tables already existed at the beginning.
|
|
|
|
self.existing_tables = set(self.tables)
|
2020-12-30 23:19:48 +00:00
|
|
|
|
|
|
|
query = 'SELECT name, sql FROM sqlite_master WHERE type == "index" AND name NOT LIKE "sqlite_%"'
|
2021-09-16 05:41:38 +00:00
|
|
|
self.indices = list(self.photodb.select(query))
|
2020-12-30 23:19:48 +00:00
|
|
|
|
2021-01-02 21:51:53 +00:00
|
|
|
def go(self):
|
|
|
|
# This loop is split in many parts, because otherwise if table A
|
2020-12-30 23:19:48 +00:00
|
|
|
# references table B and table A is completely reconstructed, it will
|
|
|
|
# be pointing to the version of B which has not been reconstructed yet,
|
|
|
|
# which is about to get renamed to B_old and then A's reference will be
|
|
|
|
# broken.
|
2022-07-16 06:00:07 +00:00
|
|
|
self.photodb.pragma_write('foreign_keys', 'OFF')
|
2022-07-16 06:47:15 +00:00
|
|
|
|
|
|
|
for (name, query) in self.indices:
|
|
|
|
self.photodb.execute(f'DROP INDEX {name}')
|
|
|
|
|
2022-10-29 21:11:29 +00:00
|
|
|
self.tables = {name: table for (name, table) in self.tables.items() if len(table) > 0}
|
|
|
|
|
|
|
|
for name in self.tables.keys():
|
2021-01-02 21:51:53 +00:00
|
|
|
if name not in self.existing_tables:
|
|
|
|
continue
|
2021-09-16 05:41:38 +00:00
|
|
|
self.photodb.execute(f'ALTER TABLE {name} RENAME TO {name}_old')
|
2020-12-30 23:19:48 +00:00
|
|
|
|
2021-01-02 21:51:53 +00:00
|
|
|
for (name, table) in self.tables.items():
|
2022-10-29 21:11:29 +00:00
|
|
|
log.debug(table['create'])
|
2021-09-16 05:41:38 +00:00
|
|
|
self.photodb.execute(table['create'])
|
2021-01-02 21:51:53 +00:00
|
|
|
|
|
|
|
for (name, table) in self.tables.items():
|
2022-10-29 21:11:29 +00:00
|
|
|
log.debug(table['transfer'])
|
2021-09-16 05:41:38 +00:00
|
|
|
self.photodb.execute(table['transfer'])
|
2021-01-02 21:51:53 +00:00
|
|
|
|
|
|
|
for (name, query) in self.tables.items():
|
|
|
|
if name not in self.existing_tables:
|
|
|
|
continue
|
2021-09-16 05:41:38 +00:00
|
|
|
self.photodb.execute(f'DROP TABLE {name}_old')
|
2020-12-30 23:19:48 +00:00
|
|
|
|
|
|
|
for (name, query) in self.indices:
|
2021-09-16 05:41:38 +00:00
|
|
|
self.photodb.execute(query)
|
2022-07-16 06:00:07 +00:00
|
|
|
self.photodb.pragma_write('foreign_keys', 'ON')
|
2020-12-30 23:19:48 +00:00
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
def upgrade_1_to_2(photodb):
|
2016-11-29 04:18:44 +00:00
|
|
|
'''
|
|
|
|
In this version, a column `tagged_at` was added to the Photos table, to keep
|
|
|
|
track of the last time the photo's tags were edited (added or removed).
|
|
|
|
'''
|
2022-07-16 06:00:07 +00:00
|
|
|
photodb.execute('ALTER TABLE photos ADD COLUMN tagged_at INT')
|
2016-11-29 04:18:44 +00:00
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
def upgrade_2_to_3(photodb):
|
2016-12-16 23:45:46 +00:00
|
|
|
'''
|
2020-12-30 23:19:48 +00:00
|
|
|
Preliminary support for user account management was added. This includes a `users` table
|
2016-12-16 23:45:46 +00:00
|
|
|
with id, username, password hash, and a timestamp.
|
|
|
|
Plus some indices.
|
|
|
|
'''
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.executescript('''
|
2020-12-30 23:19:48 +00:00
|
|
|
CREATE TABLE users(
|
2016-12-16 23:45:46 +00:00
|
|
|
id TEXT,
|
|
|
|
username TEXT COLLATE NOCASE,
|
|
|
|
password BLOB,
|
|
|
|
created INT
|
2020-12-30 23:19:48 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS index_user_id ON users(id);
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS index_user_username ON users(username COLLATE NOCASE);
|
2020-09-16 02:47:07 +00:00
|
|
|
''')
|
2016-12-16 23:45:46 +00:00
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
def upgrade_3_to_4(photodb):
|
2016-12-20 22:54:23 +00:00
|
|
|
'''
|
|
|
|
Add an `author_id` column to Photos.
|
|
|
|
'''
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.executescript('''
|
2020-12-30 23:19:48 +00:00
|
|
|
ALTER TABLE photos ADD COLUMN author_id TEXT;
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS index_photo_author ON photos(author_id);
|
|
|
|
''')
|
2016-11-29 04:18:44 +00:00
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
def upgrade_4_to_5(photodb):
|
2017-02-05 02:30:02 +00:00
|
|
|
'''
|
|
|
|
Add table `bookmarks` and its indices.
|
|
|
|
'''
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.executescript('''
|
2020-12-30 23:19:48 +00:00
|
|
|
CREATE TABLE bookmarks(
|
2017-02-05 02:30:02 +00:00
|
|
|
id TEXT,
|
|
|
|
title TEXT,
|
|
|
|
url TEXT,
|
|
|
|
author_id TEXT
|
2020-12-30 23:19:48 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS index_bookmark_id ON bookmarks(id);
|
|
|
|
|
|
|
|
CREATE INDEX IF NOT EXISTS index_bookmark_author ON bookmarks(author_id);
|
2017-02-05 02:30:02 +00:00
|
|
|
''')
|
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
def upgrade_5_to_6(photodb):
|
2017-03-04 09:13:22 +00:00
|
|
|
'''
|
|
|
|
When Albums were first introduced, they shared the ID counter and
|
|
|
|
relationship table with tags, because they were mostly identical at the time.
|
|
|
|
However this is very ugly and confusing and it's time to finally change it.
|
|
|
|
- Renames old indices `index_grouprel_*` to `index_taggroup_*`
|
|
|
|
- Creates new indices `index_albumgroup_*`
|
|
|
|
- Creates new table `album_group_rel`
|
|
|
|
- Moves all album group relationships out of `tag_group_rel` and
|
|
|
|
into `album_group_rel`
|
|
|
|
- Gives albums their own last_id value, starting with the current tag value.
|
|
|
|
'''
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute('BEGIN')
|
2017-03-04 09:13:22 +00:00
|
|
|
# 1. Start the id_numbers.albums value at the tags value so that the number
|
|
|
|
# can continue to increment safely and separately, instead of starting at
|
|
|
|
# zero and bumping into existing albums.
|
2022-06-04 02:47:27 +00:00
|
|
|
last_id = photodb.select_one_value('SELECT last_id FROM id_numbers WHERE tab == "tags"')
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute('INSERT INTO id_numbers VALUES("albums", ?)', [last_id])
|
2017-03-04 09:13:22 +00:00
|
|
|
|
|
|
|
# 2. Now's a good chance to rename 'index_grouprel' to 'index_taggroup'.
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.executescript('''
|
2020-12-30 23:19:48 +00:00
|
|
|
DROP INDEX IF EXISTS index_grouprel_parentid;
|
|
|
|
DROP INDEX IF EXISTS index_grouprel_memberid;
|
|
|
|
CREATE INDEX index_taggroup_parentid ON tag_group_rel(parentid);
|
|
|
|
CREATE INDEX index_taggroup_memberid ON tag_group_rel(memberid);
|
|
|
|
''')
|
2017-03-04 09:13:22 +00:00
|
|
|
|
|
|
|
# 3. All of the album group relationships need to be moved into their
|
|
|
|
# own table, out of tag_group_rel
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.executescript('''
|
2020-12-30 23:19:48 +00:00
|
|
|
CREATE TABLE album_group_rel(parentid TEXT, memberid TEXT);
|
|
|
|
CREATE INDEX index_albumgroup_parentid ON album_group_rel(parentid);
|
|
|
|
CREATE INDEX index_albumgroup_memberid ON album_group_rel(memberid);
|
|
|
|
''')
|
2020-09-15 21:54:44 +00:00
|
|
|
|
2021-09-16 05:41:38 +00:00
|
|
|
album_ids = list(photodb.select_column('SELECT id FROM albums'))
|
2017-03-04 09:13:22 +00:00
|
|
|
for album_id in album_ids:
|
2020-09-15 21:54:44 +00:00
|
|
|
query = 'SELECT * FROM tag_group_rel WHERE parentid == ? OR memberid == ?'
|
|
|
|
bindings = [album_id, album_id]
|
2021-09-16 05:41:38 +00:00
|
|
|
grouprels = list(photodb.select(query, bindings))
|
2020-09-15 21:54:44 +00:00
|
|
|
|
|
|
|
if not grouprels:
|
2017-03-04 09:13:22 +00:00
|
|
|
continue
|
2020-09-15 21:54:44 +00:00
|
|
|
|
|
|
|
for grouprel in grouprels:
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute('INSERT INTO album_group_rel VALUES(?, ?)', grouprel)
|
2020-09-15 21:54:44 +00:00
|
|
|
|
|
|
|
query = 'DELETE FROM tag_group_rel WHERE parentid == ? OR memberid == ?'
|
|
|
|
bindings = [album_id, album_id]
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute(query, bindings)
|
2017-03-04 09:13:22 +00:00
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
def upgrade_6_to_7(photodb):
|
2017-03-17 06:57:31 +00:00
|
|
|
'''
|
|
|
|
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.
|
2020-12-30 23:19:48 +00:00
|
|
|
|
|
|
|
Most of the indices were renamed.
|
2017-03-17 06:57:31 +00:00
|
|
|
'''
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute('BEGIN')
|
2021-08-21 05:32:19 +00:00
|
|
|
query = 'SELECT name FROM sqlite_master WHERE type == "index" AND name NOT LIKE "sqlite_%"'
|
2021-09-16 05:41:38 +00:00
|
|
|
indices = photodb.select_column(query)
|
2017-03-17 06:57:31 +00:00
|
|
|
for index in indices:
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute(f'DROP INDEX {index}')
|
2020-12-30 23:19:48 +00:00
|
|
|
|
2021-01-02 21:51:53 +00:00
|
|
|
m = Migrator(photodb)
|
|
|
|
m.tables['album_associated_directories']['create'] = '''
|
|
|
|
CREATE TABLE album_associated_directories(
|
|
|
|
albumid TEXT,
|
|
|
|
directory TEXT COLLATE NOCASE
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['album_associated_directories']['transfer'] = '''
|
|
|
|
INSERT INTO album_associated_directories SELECT
|
|
|
|
id,
|
|
|
|
associated_directory
|
|
|
|
FROM albums_old
|
|
|
|
WHERE associated_directory IS NOT NULL;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.tables['albums']['create'] = '''
|
|
|
|
CREATE TABLE albums(
|
|
|
|
id TEXT,
|
|
|
|
title TEXT,
|
|
|
|
description TEXT
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['albums']['transfer'] = '''
|
|
|
|
INSERT INTO albums SELECT
|
|
|
|
id,
|
|
|
|
title,
|
|
|
|
description
|
|
|
|
FROM albums_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.go()
|
|
|
|
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.executescript('''
|
2021-01-02 21:51:53 +00:00
|
|
|
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 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 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 INDEX IF NOT EXISTS index_albums_id on albums(id);
|
|
|
|
CREATE INDEX IF NOT EXISTS index_bookmarks_id on bookmarks(id);
|
|
|
|
CREATE INDEX IF NOT EXISTS index_bookmarks_author on bookmarks(author_id);
|
|
|
|
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 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 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 INDEX IF NOT EXISTS index_tag_synonyms_name on tag_synonyms(name);
|
|
|
|
CREATE INDEX IF NOT EXISTS index_tags_id on tags(id);
|
|
|
|
CREATE INDEX IF NOT EXISTS index_tags_name on tags(name);
|
|
|
|
CREATE INDEX IF NOT EXISTS index_users_id on users(id);
|
|
|
|
CREATE INDEX IF NOT EXISTS index_users_username on users(username COLLATE NOCASE);
|
|
|
|
''')
|
2017-03-17 06:57:31 +00:00
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
def upgrade_7_to_8(photodb):
|
2017-05-13 00:31:17 +00:00
|
|
|
'''
|
|
|
|
Give the Tags table a description field.
|
|
|
|
'''
|
2022-07-16 06:00:07 +00:00
|
|
|
photodb.executescript('ALTER TABLE tags ADD COLUMN description TEXT')
|
2017-05-13 00:31:17 +00:00
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
def upgrade_8_to_9(photodb):
|
2018-03-10 01:10:27 +00:00
|
|
|
'''
|
|
|
|
Give the Photos table a searchhidden field.
|
|
|
|
'''
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.executescript('''
|
2020-12-30 23:19:48 +00:00
|
|
|
ALTER TABLE photos ADD COLUMN searchhidden INT;
|
|
|
|
|
|
|
|
UPDATE photos SET searchhidden = 0;
|
|
|
|
|
|
|
|
CREATE INDEX index_photos_searchhidden on photos(searchhidden);
|
|
|
|
''')
|
2017-03-17 06:57:31 +00:00
|
|
|
|
2018-03-13 09:50:54 +00:00
|
|
|
def upgrade_9_to_10(photodb):
|
|
|
|
'''
|
|
|
|
From now on, the filepath stored in Photo's thumbnail column should be a
|
|
|
|
relative path where . is the PhotoDB's thumbnail_directory.
|
|
|
|
Previously, the stored path was unnecessarily high and contained the PDB's
|
|
|
|
data_directory, reducing portability.
|
|
|
|
'''
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute('BEGIN')
|
2020-12-30 23:19:48 +00:00
|
|
|
photos = list(photodb.search(has_thumbnail=True, is_searchhidden=None, yield_albums=False))
|
2018-03-13 09:50:54 +00:00
|
|
|
|
|
|
|
# Since we're doing it all at once, I'm going to cheat and skip the
|
|
|
|
# relative_to() calculation.
|
|
|
|
thumbnail_dir = photodb.thumbnail_directory.absolute_path
|
|
|
|
for photo in photos:
|
|
|
|
new_thumbnail_path = photo.make_thumbnail_filepath()
|
|
|
|
new_thumbnail_path = new_thumbnail_path.absolute_path
|
|
|
|
new_thumbnail_path = '.' + new_thumbnail_path.replace(thumbnail_dir, '')
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute(
|
2020-12-30 23:19:48 +00:00
|
|
|
'UPDATE photos SET thumbnail = ? WHERE id == ?',
|
|
|
|
[new_thumbnail_path, photo.id]
|
|
|
|
)
|
2018-03-13 09:50:54 +00:00
|
|
|
|
2018-03-18 07:09:08 +00:00
|
|
|
def upgrade_10_to_11(photodb):
|
|
|
|
'''
|
2018-03-18 22:28:26 +00:00
|
|
|
Added Primary keys, Foreign keys, and NOT NULL constraints.
|
|
|
|
Added author_id column to Album and Tag tables.
|
|
|
|
'''
|
2021-01-02 21:51:53 +00:00
|
|
|
m = Migrator(photodb)
|
|
|
|
|
|
|
|
m.tables['albums']['create'] = '''
|
|
|
|
CREATE TABLE albums(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
title TEXT,
|
|
|
|
description TEXT,
|
|
|
|
author_id TEXT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['albums']['transfer'] = '''
|
|
|
|
INSERT INTO albums SELECT
|
|
|
|
id,
|
|
|
|
title,
|
|
|
|
description,
|
|
|
|
NULL
|
|
|
|
FROM albums_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.tables['tags']['create'] = '''
|
|
|
|
CREATE TABLE tags(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
name TEXT NOT NULL,
|
|
|
|
description TEXT,
|
|
|
|
author_id TEXT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['tags']['transfer'] = '''
|
|
|
|
INSERT INTO tags SELECT
|
|
|
|
id,
|
|
|
|
name,
|
|
|
|
description,
|
|
|
|
NULL
|
|
|
|
FROM tags_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.go()
|
2018-03-18 07:09:08 +00:00
|
|
|
|
2018-03-22 02:00:13 +00:00
|
|
|
def upgrade_11_to_12(photodb):
|
|
|
|
'''
|
|
|
|
Added multicolumn (photoid, tagid) index to the photo_tag_rel table to
|
|
|
|
improve the speed of individual relation searching, important for the
|
|
|
|
new intersection-based search.
|
|
|
|
'''
|
2022-07-16 06:00:07 +00:00
|
|
|
photodb.execute('''
|
2020-12-30 23:19:48 +00:00
|
|
|
CREATE INDEX IF NOT EXISTS index_photo_tag_rel_photoid_tagid on photo_tag_rel(photoid, tagid);
|
|
|
|
''')
|
2018-03-22 02:00:13 +00:00
|
|
|
|
2018-04-15 21:23:24 +00:00
|
|
|
def upgrade_12_to_13(photodb):
|
|
|
|
'''
|
|
|
|
Added display_name column to the User table.
|
|
|
|
'''
|
2021-01-02 21:51:53 +00:00
|
|
|
m = Migrator(photodb)
|
|
|
|
m.tables['users']['create'] = '''
|
|
|
|
CREATE TABLE users(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
username TEXT NOT NULL COLLATE NOCASE,
|
|
|
|
password BLOB NOT NULL,
|
|
|
|
display_name TEXT,
|
|
|
|
created INT
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['users']['transfer'] = '''
|
|
|
|
INSERT INTO users SELECT
|
|
|
|
id,
|
|
|
|
username,
|
|
|
|
password,
|
|
|
|
NULL,
|
|
|
|
created
|
|
|
|
FROM users_old;
|
|
|
|
'''
|
2018-04-15 21:23:24 +00:00
|
|
|
|
2018-04-15 21:32:18 +00:00
|
|
|
def upgrade_13_to_14(photodb):
|
|
|
|
'''
|
|
|
|
Rename user.min_length to min_username_length.
|
|
|
|
'''
|
|
|
|
photodb.config['user']['min_username_length'] = photodb.config['user'].pop('min_length')
|
|
|
|
photodb.config['user']['max_username_length'] = photodb.config['user'].pop('max_length')
|
|
|
|
photodb.save_config()
|
|
|
|
|
2020-09-15 21:56:45 +00:00
|
|
|
def upgrade_14_to_15(photodb):
|
|
|
|
'''
|
|
|
|
Added the dev_ino column to photos.
|
|
|
|
'''
|
2021-01-02 21:51:53 +00:00
|
|
|
m = Migrator(photodb)
|
|
|
|
m.tables['photos']['create'] = '''
|
|
|
|
CREATE TABLE photos(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
filepath TEXT COLLATE NOCASE,
|
|
|
|
dev_ino TEXT,
|
|
|
|
override_filename TEXT COLLATE NOCASE,
|
|
|
|
extension TEXT,
|
|
|
|
width INT,
|
|
|
|
height INT,
|
|
|
|
ratio REAL,
|
|
|
|
area INT,
|
|
|
|
duration INT,
|
|
|
|
bytes INT,
|
|
|
|
created INT,
|
|
|
|
thumbnail TEXT,
|
|
|
|
tagged_at INT,
|
|
|
|
author_id TEXT,
|
|
|
|
searchhidden INT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['photos']['transfer'] = '''
|
|
|
|
INSERT INTO photos SELECT
|
|
|
|
id,
|
|
|
|
filepath,
|
|
|
|
NULL,
|
|
|
|
override_filename,
|
|
|
|
extension,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
ratio,
|
|
|
|
area,
|
|
|
|
duration,
|
|
|
|
bytes,
|
|
|
|
created,
|
|
|
|
thumbnail,
|
|
|
|
tagged_at,
|
|
|
|
author_id,
|
|
|
|
searchhidden
|
|
|
|
FROM photos_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.go()
|
|
|
|
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute('CREATE INDEX index_photos_dev_ino ON photos(dev_ino);')
|
2020-12-30 23:19:48 +00:00
|
|
|
|
2020-09-15 21:56:45 +00:00
|
|
|
for photo in photodb.get_photos_by_recent():
|
|
|
|
if not photo.real_path.is_file:
|
|
|
|
continue
|
|
|
|
stat = photo.real_path.stat
|
|
|
|
(dev, ino) = (stat.st_dev, stat.st_ino)
|
|
|
|
if dev == 0 or ino == 0:
|
|
|
|
continue
|
|
|
|
dev_ino = f'{dev},{ino}'
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute('UPDATE photos SET dev_ino = ? WHERE id == ?', [dev_ino, photo.id])
|
2020-09-15 21:56:45 +00:00
|
|
|
|
2020-12-30 23:28:52 +00:00
|
|
|
def upgrade_15_to_16(photodb):
|
|
|
|
'''
|
|
|
|
Added the basename column to photos. Added collate nocase to extension.
|
|
|
|
'''
|
2021-01-02 21:51:53 +00:00
|
|
|
m = Migrator(photodb)
|
|
|
|
m.tables['photos']['create'] = '''
|
|
|
|
CREATE TABLE photos(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
filepath TEXT COLLATE NOCASE,
|
|
|
|
dev_ino TEXT,
|
|
|
|
basename TEXT COLLATE NOCASE,
|
|
|
|
override_filename TEXT COLLATE NOCASE,
|
|
|
|
extension TEXT COLLATE NOCASE,
|
|
|
|
width INT,
|
|
|
|
height INT,
|
|
|
|
ratio REAL,
|
|
|
|
area INT,
|
|
|
|
duration INT,
|
|
|
|
bytes INT,
|
|
|
|
created INT,
|
|
|
|
thumbnail TEXT,
|
|
|
|
tagged_at INT,
|
|
|
|
author_id TEXT,
|
|
|
|
searchhidden INT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['photos']['transfer'] = '''
|
|
|
|
INSERT INTO photos SELECT
|
|
|
|
id,
|
|
|
|
filepath,
|
|
|
|
dev_ino,
|
|
|
|
NULL,
|
|
|
|
override_filename,
|
|
|
|
extension,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
ratio,
|
|
|
|
area,
|
|
|
|
duration,
|
|
|
|
bytes,
|
|
|
|
created,
|
|
|
|
thumbnail,
|
|
|
|
tagged_at,
|
|
|
|
author_id,
|
|
|
|
searchhidden
|
|
|
|
FROM photos_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.go()
|
2020-12-30 23:28:52 +00:00
|
|
|
|
2021-09-16 05:41:38 +00:00
|
|
|
for (id, filepath) in photodb.select('SELECT id, filepath FROM photos'):
|
2020-12-30 23:28:52 +00:00
|
|
|
basename = os.path.basename(filepath)
|
2021-09-16 05:41:38 +00:00
|
|
|
photodb.execute('UPDATE photos SET basename = ? WHERE id == ?', [basename, id])
|
2020-12-30 23:28:52 +00:00
|
|
|
|
2021-01-08 07:05:43 +00:00
|
|
|
def upgrade_16_to_17(photodb):
|
|
|
|
'''
|
|
|
|
Added the created column to albums, bookmarks, tags.
|
|
|
|
'''
|
|
|
|
m = Migrator(photodb)
|
|
|
|
m.tables['albums']['create'] = '''
|
|
|
|
CREATE TABLE albums(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
title TEXT,
|
|
|
|
description TEXT,
|
|
|
|
created INT,
|
|
|
|
author_id TEXT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['albums']['transfer'] = '''
|
|
|
|
INSERT INTO albums SELECT
|
|
|
|
id,
|
|
|
|
title,
|
|
|
|
description,
|
|
|
|
0,
|
|
|
|
author_id
|
|
|
|
FROM albums_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.tables['bookmarks']['create'] = '''
|
|
|
|
CREATE TABLE bookmarks(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
title TEXT,
|
|
|
|
url TEXT,
|
|
|
|
created INT,
|
|
|
|
author_id TEXT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['bookmarks']['transfer'] = '''
|
|
|
|
INSERT INTO bookmarks SELECT
|
|
|
|
id,
|
|
|
|
title,
|
|
|
|
url,
|
|
|
|
0,
|
|
|
|
author_id
|
|
|
|
FROM bookmarks_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.tables['tags']['create'] = '''
|
|
|
|
CREATE TABLE tags(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
name TEXT NOT NULL,
|
|
|
|
description TEXT,
|
|
|
|
created INT,
|
|
|
|
author_id TEXT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['tags']['transfer'] = '''
|
|
|
|
INSERT INTO tags SELECT
|
|
|
|
id,
|
|
|
|
name,
|
|
|
|
description,
|
|
|
|
0,
|
|
|
|
author_id
|
|
|
|
FROM tags_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.go()
|
|
|
|
|
2021-01-19 18:35:58 +00:00
|
|
|
def upgrade_17_to_18(photodb):
|
|
|
|
'''
|
|
|
|
Added the thumbnail_photo column to albums.
|
|
|
|
'''
|
|
|
|
m = Migrator(photodb)
|
|
|
|
m.tables['albums']['create'] = '''
|
|
|
|
CREATE TABLE albums(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
title TEXT,
|
|
|
|
description TEXT,
|
|
|
|
created INT,
|
|
|
|
thumbnail_photo TEXT,
|
|
|
|
author_id TEXT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id),
|
|
|
|
FOREIGN KEY(thumbnail_photo) REFERENCES photos(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['albums']['transfer'] = '''
|
|
|
|
INSERT INTO albums SELECT
|
|
|
|
id,
|
|
|
|
title,
|
|
|
|
description,
|
|
|
|
created,
|
|
|
|
NULL,
|
|
|
|
author_id
|
|
|
|
FROM albums_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.go()
|
|
|
|
|
2021-02-03 20:12:47 +00:00
|
|
|
def upgrade_18_to_19(photodb):
|
|
|
|
m = Migrator(photodb)
|
|
|
|
|
|
|
|
m.tables['photos']['create'] = '''
|
|
|
|
CREATE TABLE photos(
|
|
|
|
id TEXT PRIMARY KEY NOT NULL,
|
|
|
|
filepath TEXT COLLATE NOCASE,
|
|
|
|
basename TEXT COLLATE NOCASE,
|
|
|
|
override_filename TEXT COLLATE NOCASE,
|
|
|
|
extension TEXT COLLATE NOCASE,
|
|
|
|
mtime INT,
|
|
|
|
sha256 TEXT,
|
|
|
|
width INT,
|
|
|
|
height INT,
|
|
|
|
ratio REAL,
|
|
|
|
area INT,
|
|
|
|
duration INT,
|
|
|
|
bytes INT,
|
|
|
|
created INT,
|
|
|
|
thumbnail TEXT,
|
|
|
|
tagged_at INT,
|
|
|
|
author_id TEXT,
|
|
|
|
searchhidden INT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['photos']['transfer'] = '''
|
|
|
|
INSERT INTO photos SELECT
|
|
|
|
id,
|
|
|
|
filepath,
|
|
|
|
basename,
|
|
|
|
override_filename,
|
|
|
|
extension,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
ratio,
|
|
|
|
area,
|
|
|
|
duration,
|
|
|
|
bytes,
|
|
|
|
created,
|
|
|
|
thumbnail,
|
|
|
|
tagged_at,
|
|
|
|
author_id,
|
|
|
|
searchhidden
|
|
|
|
FROM photos_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.go()
|
|
|
|
|
2021-09-30 23:55:13 +00:00
|
|
|
def upgrade_19_to_20(photodb):
|
|
|
|
'''
|
|
|
|
In this version, the thumbnail folder was renamed from "site_thumbnails"
|
|
|
|
to just "thumbnails".
|
|
|
|
'''
|
|
|
|
old = photodb.data_directory.with_child('site_thumbnails')
|
|
|
|
if not old.exists:
|
|
|
|
return
|
|
|
|
new = photodb.data_directory.with_child('thumbnails')
|
|
|
|
if new.exists:
|
|
|
|
if len(new.listdir()) > 0:
|
|
|
|
raise Exception(f'{new.absolute_path} already has items in it.')
|
|
|
|
else:
|
2021-12-07 20:45:08 +00:00
|
|
|
os.rmdir(new)
|
2021-10-05 00:23:58 +00:00
|
|
|
|
|
|
|
photodb.execute('UPDATE photos SET thumbnail = REPLACE(thumbnail, "/site_thumbnails/", "/thumbnails/")')
|
|
|
|
photodb.execute('UPDATE photos SET thumbnail = REPLACE(thumbnail, "\\site_thumbnails\\", "\\thumbnails\\")')
|
2021-12-07 20:45:08 +00:00
|
|
|
photodb.on_commit_queue.append({'action': os.rename, 'args': (old, new)})
|
2021-09-30 23:55:13 +00:00
|
|
|
|
2022-07-16 06:47:15 +00:00
|
|
|
def upgrade_20_to_21(photodb):
|
|
|
|
'''
|
|
|
|
In this version, the object IDs were migrated from string to int.
|
|
|
|
'''
|
|
|
|
m = Migrator(photodb)
|
|
|
|
|
|
|
|
m.tables['albums']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS albums(
|
|
|
|
id INT PRIMARY KEY NOT NULL,
|
|
|
|
title TEXT,
|
|
|
|
description TEXT,
|
|
|
|
created INT,
|
|
|
|
thumbnail_photo INT,
|
|
|
|
author_id INT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id),
|
|
|
|
FOREIGN KEY(thumbnail_photo) REFERENCES photos(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['albums']['transfer'] = 'INSERT INTO albums SELECT * FROM albums_old'
|
|
|
|
|
|
|
|
m.tables['bookmarks']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS bookmarks(
|
|
|
|
id INT PRIMARY KEY NOT NULL,
|
|
|
|
title TEXT,
|
|
|
|
url TEXT,
|
|
|
|
created INT,
|
|
|
|
author_id INT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['bookmarks']['transfer'] = 'INSERT INTO bookmarks SELECT * FROM bookmarks_old'
|
|
|
|
|
|
|
|
m.tables['photos']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS photos(
|
|
|
|
id INT PRIMARY KEY NOT NULL,
|
|
|
|
filepath TEXT COLLATE NOCASE,
|
|
|
|
basename TEXT COLLATE NOCASE,
|
|
|
|
override_filename TEXT COLLATE NOCASE,
|
|
|
|
extension TEXT COLLATE NOCASE,
|
|
|
|
mtime INT,
|
|
|
|
sha256 TEXT,
|
|
|
|
width INT,
|
|
|
|
height INT,
|
|
|
|
ratio REAL,
|
|
|
|
area INT,
|
|
|
|
duration INT,
|
|
|
|
bytes INT,
|
|
|
|
created INT,
|
|
|
|
thumbnail TEXT,
|
|
|
|
tagged_at INT,
|
|
|
|
author_id INT,
|
|
|
|
searchhidden INT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['photos']['transfer'] = 'INSERT INTO photos SELECT * FROM photos_old'
|
|
|
|
|
|
|
|
m.tables['tags']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS tags(
|
|
|
|
id INT PRIMARY KEY NOT NULL,
|
|
|
|
name TEXT NOT NULL,
|
|
|
|
description TEXT,
|
|
|
|
created INT,
|
|
|
|
author_id INT,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['tags']['transfer'] = 'INSERT INTO tags SELECT * FROM tags_old'
|
|
|
|
|
|
|
|
m.tables['users']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS users(
|
|
|
|
id INT PRIMARY KEY NOT NULL,
|
|
|
|
username TEXT UNIQUE NOT NULL COLLATE NOCASE,
|
|
|
|
password BLOB NOT NULL,
|
|
|
|
display_name TEXT,
|
|
|
|
created INT
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['users']['transfer'] = 'INSERT INTO users SELECT * FROM users_old'
|
|
|
|
|
|
|
|
m.tables['album_associated_directories']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS album_associated_directories(
|
|
|
|
albumid INT NOT NULL,
|
|
|
|
directory TEXT NOT NULL COLLATE NOCASE,
|
|
|
|
FOREIGN KEY(albumid) REFERENCES albums(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['album_associated_directories']['transfer'] = 'INSERT INTO album_associated_directories SELECT * FROM album_associated_directories_old'
|
|
|
|
|
|
|
|
m.tables['album_group_rel']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS album_group_rel(
|
|
|
|
parentid INT NOT NULL,
|
|
|
|
memberid INT NOT NULL,
|
|
|
|
FOREIGN KEY(parentid) REFERENCES albums(id),
|
|
|
|
FOREIGN KEY(memberid) REFERENCES albums(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['album_group_rel']['transfer'] = 'INSERT INTO album_group_rel SELECT * FROM album_group_rel_old'
|
|
|
|
|
|
|
|
m.tables['album_photo_rel']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS album_photo_rel(
|
|
|
|
albumid INT NOT NULL,
|
|
|
|
photoid INT NOT NULL,
|
|
|
|
FOREIGN KEY(albumid) REFERENCES albums(id),
|
|
|
|
FOREIGN KEY(photoid) REFERENCES photos(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['album_photo_rel']['transfer'] = 'INSERT INTO album_photo_rel SELECT * FROM album_photo_rel_old'
|
|
|
|
|
|
|
|
m.tables['photo_tag_rel']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS photo_tag_rel(
|
|
|
|
photoid INT NOT NULL,
|
|
|
|
tagid INT NOT NULL,
|
|
|
|
FOREIGN KEY(photoid) REFERENCES photos(id),
|
|
|
|
FOREIGN KEY(tagid) REFERENCES tags(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['photo_tag_rel']['transfer'] = 'INSERT INTO photo_tag_rel SELECT * FROM photo_tag_rel_old'
|
|
|
|
|
|
|
|
m.tables['tag_group_rel']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS tag_group_rel(
|
|
|
|
parentid INT NOT NULL,
|
|
|
|
memberid INT NOT NULL,
|
|
|
|
FOREIGN KEY(parentid) REFERENCES tags(id),
|
|
|
|
FOREIGN KEY(memberid) REFERENCES tags(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['tag_group_rel']['transfer'] = 'INSERT INTO tag_group_rel SELECT * FROM tag_group_rel_old'
|
|
|
|
|
|
|
|
m.go()
|
|
|
|
|
|
|
|
users = list(photodb.get_users())
|
|
|
|
for user in users:
|
|
|
|
old_id = user.id
|
|
|
|
new_id = photodb.generate_id(etiquette.objects.User)
|
|
|
|
photodb.execute('UPDATE users SET id = ? WHERE id = ?', [new_id, old_id])
|
|
|
|
photodb.execute('UPDATE albums SET author_id = ? WHERE author_id = ?', [new_id, old_id])
|
|
|
|
photodb.execute('UPDATE bookmarks SET author_id = ? WHERE author_id = ?', [new_id, old_id])
|
|
|
|
photodb.execute('UPDATE photos SET author_id = ? WHERE author_id = ?', [new_id, old_id])
|
|
|
|
photodb.execute('UPDATE tags SET author_id = ? WHERE author_id = ?', [new_id, old_id])
|
|
|
|
|
|
|
|
def movethumbnail(old_thumbnail, new_thumbnail):
|
|
|
|
new_thumbnail.parent.makedirs(exist_ok=True)
|
|
|
|
shutil.move(old_thumbnail.absolute_path, new_thumbnail.absolute_path)
|
|
|
|
|
2022-10-29 20:55:35 +00:00
|
|
|
rows = photodb.select('SELECT id, thumbnail FROM photos where thumbnail IS NOT NULL')
|
|
|
|
for row in rows:
|
|
|
|
photo_id = row['id']
|
|
|
|
chunked_id = [''.join(chunk) for chunk in gentools.chunk_generator(str(photo_id), 3)]
|
|
|
|
folder = chunked_id[:-1]
|
|
|
|
folder = os.sep.join(folder)
|
|
|
|
folder = photodb.thumbnail_directory.join(folder)
|
|
|
|
old_thumbnail = photodb.thumbnail_directory.join(row['thumbnail'])
|
|
|
|
new_thumbnail = folder.with_child(f'{photo_id}.jpg')
|
2022-07-16 06:47:15 +00:00
|
|
|
print(old_thumbnail, new_thumbnail)
|
2022-08-14 00:48:26 +00:00
|
|
|
photodb.on_commit_queue.append({'action': movethumbnail, 'args': (old_thumbnail, new_thumbnail)})
|
2022-07-16 06:47:15 +00:00
|
|
|
store_as = new_thumbnail.relative_to(photodb.thumbnail_directory)
|
2022-10-29 20:55:35 +00:00
|
|
|
photodb.update(table=etiquette.objects.Photo, pairs={'id': photo_id, 'thumbnail': store_as}, where_key='id')
|
2022-07-16 06:47:15 +00:00
|
|
|
|
2022-08-14 01:08:45 +00:00
|
|
|
def upgrade_21_to_22(photodb):
|
|
|
|
m = Migrator(photodb)
|
|
|
|
|
|
|
|
m.tables['photos']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS photos(
|
|
|
|
id INT PRIMARY KEY NOT NULL,
|
|
|
|
filepath TEXT COLLATE NOCASE,
|
|
|
|
override_filename TEXT COLLATE NOCASE,
|
|
|
|
mtime INT,
|
|
|
|
sha256 TEXT,
|
|
|
|
width INT,
|
|
|
|
height INT,
|
|
|
|
duration INT,
|
|
|
|
bytes INT,
|
|
|
|
created INT,
|
|
|
|
thumbnail TEXT,
|
|
|
|
tagged_at INT,
|
|
|
|
author_id INT,
|
|
|
|
searchhidden INT,
|
|
|
|
-- GENERATED COLUMNS
|
|
|
|
area INT GENERATED ALWAYS AS (width * height) VIRTUAL,
|
|
|
|
aspectratio REAL GENERATED ALWAYS AS (1.0 * width / height) VIRTUAL,
|
|
|
|
-- Thank you ungalcrys
|
|
|
|
-- https://stackoverflow.com/a/38330814/5430534
|
|
|
|
basename TEXT GENERATED ALWAYS AS (
|
|
|
|
COALESCE(
|
|
|
|
override_filename,
|
|
|
|
replace(filepath, rtrim(filepath, replace(replace(filepath, '\\', '/'), '/', '')), '')
|
|
|
|
)
|
|
|
|
) STORED COLLATE NOCASE,
|
|
|
|
extension TEXT GENERATED ALWAYS AS (
|
|
|
|
replace(basename, rtrim(basename, replace(basename, '.', '')), '')
|
|
|
|
) VIRTUAL COLLATE NOCASE,
|
|
|
|
bitrate REAL GENERATED ALWAYS AS ((bytes / 128) / duration) VIRTUAL,
|
|
|
|
FOREIGN KEY(author_id) REFERENCES users(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['photos']['transfer'] = '''
|
|
|
|
INSERT INTO photos SELECT
|
|
|
|
id,
|
|
|
|
filepath,
|
|
|
|
override_filename,
|
|
|
|
mtime,
|
|
|
|
sha256,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
duration,
|
|
|
|
bytes,
|
|
|
|
created,
|
|
|
|
thumbnail,
|
|
|
|
tagged_at,
|
|
|
|
author_id,
|
|
|
|
searchhidden
|
|
|
|
FROM photos_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.go()
|
|
|
|
|
2022-10-29 20:56:17 +00:00
|
|
|
photodb.execute('DROP INDEX IF EXISTS index_photos_override_filename')
|
2022-08-14 01:08:45 +00:00
|
|
|
photodb.execute('CREATE INDEX IF NOT EXISTS index_photos_basename on photos(basename COLLATE NOCASE)')
|
|
|
|
|
2022-10-29 21:21:06 +00:00
|
|
|
def upgrade_22_to_23(photodb):
|
|
|
|
'''
|
|
|
|
In this version, the rel tables received explicit primary keys and
|
|
|
|
a `created` column.
|
|
|
|
'''
|
|
|
|
m = Migrator(photodb)
|
|
|
|
|
|
|
|
m.tables['album_associated_directories']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS album_associated_directories(
|
|
|
|
albumid INT NOT NULL,
|
|
|
|
directory TEXT NOT NULL COLLATE NOCASE,
|
|
|
|
created INT,
|
|
|
|
FOREIGN KEY(albumid) REFERENCES albums(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['album_associated_directories']['transfer'] = '''
|
|
|
|
INSERT INTO album_associated_directories SELECT
|
|
|
|
albumid,
|
|
|
|
directory,
|
|
|
|
(SELECT created FROM albums WHERE id=albumid)
|
|
|
|
FROM album_associated_directories_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.tables['album_group_rel']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS album_group_rel(
|
|
|
|
parentid INT NOT NULL,
|
|
|
|
memberid INT NOT NULL,
|
|
|
|
created INT,
|
|
|
|
PRIMARY KEY(parentid, memberid),
|
|
|
|
FOREIGN KEY(parentid) REFERENCES albums(id),
|
|
|
|
FOREIGN KEY(memberid) REFERENCES albums(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['album_group_rel']['transfer'] = '''
|
|
|
|
INSERT INTO album_group_rel SELECT
|
|
|
|
parentid,
|
|
|
|
memberid,
|
|
|
|
MAX((SELECT created FROM albums WHERE id=parentid), (SELECT created FROM albums WHERE id=memberid))
|
|
|
|
FROM album_group_rel_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.tables['album_photo_rel']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS album_photo_rel(
|
|
|
|
albumid INT NOT NULL,
|
|
|
|
photoid INT NOT NULL,
|
|
|
|
created INT,
|
|
|
|
PRIMARY KEY(albumid, photoid),
|
|
|
|
FOREIGN KEY(albumid) REFERENCES albums(id),
|
|
|
|
FOREIGN KEY(photoid) REFERENCES photos(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['album_photo_rel']['transfer'] = '''
|
|
|
|
INSERT INTO album_photo_rel SELECT
|
|
|
|
albumid,
|
|
|
|
photoid,
|
|
|
|
MAX((SELECT created FROM albums WHERE id=albumid), (SELECT created FROM photos WHERE id=photoid))
|
|
|
|
FROM album_photo_rel_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.tables['photo_tag_rel']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS photo_tag_rel(
|
|
|
|
photoid INT NOT NULL,
|
|
|
|
tagid INT NOT NULL,
|
|
|
|
created INT,
|
|
|
|
PRIMARY KEY(photoid, tagid),
|
|
|
|
FOREIGN KEY(photoid) REFERENCES photos(id),
|
|
|
|
FOREIGN KEY(tagid) REFERENCES tags(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['photo_tag_rel']['transfer'] = '''
|
|
|
|
INSERT INTO photo_tag_rel SELECT
|
|
|
|
photoid,
|
|
|
|
tagid,
|
|
|
|
MAX((SELECT created FROM photos WHERE id=photoid), (SELECT created FROM tags WHERE id=tagid))
|
|
|
|
FROM photo_tag_rel_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.tables['tag_group_rel']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS tag_group_rel(
|
|
|
|
parentid INT NOT NULL,
|
|
|
|
memberid INT NOT NULL,
|
|
|
|
created INT,
|
|
|
|
PRIMARY KEY(parentid, memberid),
|
|
|
|
FOREIGN KEY(parentid) REFERENCES tags(id),
|
|
|
|
FOREIGN KEY(memberid) REFERENCES tags(id)
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['tag_group_rel']['transfer'] = '''
|
|
|
|
INSERT INTO tag_group_rel SELECT
|
|
|
|
parentid,
|
|
|
|
memberid,
|
|
|
|
MAX((SELECT created FROM tags WHERE id=parentid), (SELECT created FROM tags WHERE id=memberid))
|
|
|
|
FROM tag_group_rel_old;
|
|
|
|
'''
|
|
|
|
|
|
|
|
m.tables['tag_synonyms']['create'] = '''
|
|
|
|
CREATE TABLE IF NOT EXISTS tag_synonyms(
|
|
|
|
name TEXT NOT NULL,
|
|
|
|
mastername TEXT NOT NULL,
|
|
|
|
created INT
|
|
|
|
);
|
|
|
|
'''
|
|
|
|
m.tables['tag_synonyms']['transfer'] = '''
|
|
|
|
INSERT INTO tag_synonyms SELECT
|
|
|
|
name,
|
|
|
|
mastername,
|
|
|
|
(SELECT COALESCE(created, 0) FROM tags WHERE tags.name=name)
|
|
|
|
FROM tag_synonyms_old;
|
|
|
|
'''
|
|
|
|
m.go()
|
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
def upgrade_all(data_directory):
|
2016-11-29 04:18:44 +00:00
|
|
|
'''
|
2018-03-13 09:28:09 +00:00
|
|
|
Given the directory containing a phototagger database, apply all of the
|
|
|
|
needed upgrade_x_to_y functions in order.
|
2016-11-29 04:18:44 +00:00
|
|
|
'''
|
2018-03-13 09:28:09 +00:00
|
|
|
photodb = etiquette.photodb.PhotoDB(data_directory, create=False, skip_version_check=True)
|
2016-11-29 04:18:44 +00:00
|
|
|
|
2022-07-16 06:00:07 +00:00
|
|
|
current_version = photodb.pragma_read('user_version')
|
2018-03-10 01:10:27 +00:00
|
|
|
needed_version = etiquette.constants.DATABASE_VERSION
|
2016-11-29 04:18:44 +00:00
|
|
|
|
|
|
|
if current_version == needed_version:
|
2018-03-18 07:09:08 +00:00
|
|
|
print('Already up to date with version %d.' % needed_version)
|
2022-07-16 06:00:07 +00:00
|
|
|
photodb.close()
|
2016-11-29 04:18:44 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
for version_number in range(current_version + 1, needed_version + 1):
|
2018-03-18 07:09:08 +00:00
|
|
|
print('Upgrading from %d to %d.' % (current_version, version_number))
|
2016-11-29 04:18:44 +00:00
|
|
|
upgrade_function = 'upgrade_%d_to_%d' % (current_version, version_number)
|
|
|
|
upgrade_function = eval(upgrade_function)
|
2020-08-11 01:50:54 +00:00
|
|
|
|
2022-07-16 06:00:07 +00:00
|
|
|
photodb.pragma_write('journal_mode', 'wal')
|
|
|
|
with photodb.transaction:
|
|
|
|
photodb.pragma_write('foreign_keys', 'ON')
|
2020-08-11 01:50:54 +00:00
|
|
|
upgrade_function(photodb)
|
2022-07-16 06:00:07 +00:00
|
|
|
photodb.pragma_write('user_version', version_number)
|
2020-08-11 01:50:54 +00:00
|
|
|
|
2016-11-29 04:18:44 +00:00
|
|
|
current_version = version_number
|
2022-07-16 06:00:07 +00:00
|
|
|
photodb.close()
|
2016-11-29 04:18:44 +00:00
|
|
|
print('Upgrades finished.')
|
|
|
|
|
|
|
|
def upgrade_all_argparse(args):
|
2018-03-13 09:28:09 +00:00
|
|
|
return upgrade_all(data_directory=args.data_directory)
|
2016-11-29 04:18:44 +00:00
|
|
|
|
2022-07-16 06:00:07 +00:00
|
|
|
@vlogging.main_decorator
|
2016-11-29 04:18:44 +00:00
|
|
|
def main(argv):
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
|
2018-03-13 09:28:09 +00:00
|
|
|
parser.add_argument('data_directory')
|
2016-11-29 04:18:44 +00:00
|
|
|
parser.set_defaults(func=upgrade_all_argparse)
|
|
|
|
|
|
|
|
args = parser.parse_args(argv)
|
2020-02-09 01:24:57 +00:00
|
|
|
return args.func(args)
|
2016-11-29 04:18:44 +00:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2020-02-09 01:24:57 +00:00
|
|
|
raise SystemExit(main(sys.argv[1:]))
|