Set up foreign keys

This commit is contained in:
Alex Ling 2021-01-17 04:47:06 +00:00
parent 959560c7a7
commit 7a09c9006a
2 changed files with 100 additions and 17 deletions

View File

@ -0,0 +1,85 @@
class ForeignKeys < MG::Base
def up : String
<<-SQL
-- add foreign key to tags
ALTER TABLE tags RENAME TO tmp;
CREATE TABLE tags (
id TEXT NOT NULL,
tag TEXT NOT NULL,
UNIQUE (id, tag),
FOREIGN KEY (id) REFERENCES titles (id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
INSERT INTO tags
SELECT * FROM tmp;
DROP TABLE tmp;
CREATE INDEX tags_id_idx ON tags (id);
CREATE INDEX tags_tag_idx ON tags (tag);
-- add foreign key to thumbnails
ALTER TABLE thumbnails RENAME TO tmp;
CREATE TABLE thumbnails (
id TEXT NOT NULL,
data BLOB NOT NULL,
filename TEXT NOT NULL,
mime TEXT NOT NULL,
size INTEGER NOT NULL,
FOREIGN KEY (id) REFERENCES ids (id)
ON UPDATE CASCADE
ON DELETE CASCADE
);
INSERT INTO thumbnails
SELECT * FROM tmp;
DROP TABLE tmp;
CREATE UNIQUE INDEX tn_index ON thumbnails (id);
SQL
end
def down : String
<<-SQL
-- remove foreign key from thumbnails
ALTER TABLE thumbnails RENAME TO tmp;
CREATE TABLE thumbnails (
id TEXT NOT NULL,
data BLOB NOT NULL,
filename TEXT NOT NULL,
mime TEXT NOT NULL,
size INTEGER NOT NULL
);
INSERT INTO thumbnails
SELECT * FROM tmp;
DROP TABLE tmp;
CREATE UNIQUE INDEX tn_index ON thumbnails (id);
-- remove foreign key from tags
ALTER TABLE tags RENAME TO tmp;
CREATE TABLE tags (
id TEXT NOT NULL,
tag TEXT NOT NULL,
UNIQUE (id, tag)
);
INSERT INTO tags
SELECT * FROM tmp;
DROP TABLE tmp;
CREATE INDEX tags_id_idx ON tags (id);
CREATE INDEX tags_tag_idx ON tags (tag);
SQL
end
end

View File

@ -78,9 +78,11 @@ class Storage
private def get_db(&block : DB::Database ->) private def get_db(&block : DB::Database ->)
if @db.nil? if @db.nil?
DB.open "sqlite3://#{@path}" do |db| DB.open "sqlite3://#{@path}" do |db|
db.exec "PRAGMA foreign_keys = 1"
yield db yield db
end end
else else
@db.not_nil!.exec "PRAGMA foreign_keys = 1"
yield @db.not_nil! yield @db.not_nil!
end end
end end
@ -361,6 +363,7 @@ class Storage
MainFiber.run do MainFiber.run do
Logger.info "Starting DB optimization" Logger.info "Starting DB optimization"
get_db do |db| get_db do |db|
# Delete dangling entry IDs
trash_ids = [] of String trash_ids = [] of String
db.query "select path, id from ids" do |rs| db.query "select path, id from ids" do |rs|
rs.each do rs.each do
@ -369,29 +372,24 @@ class Storage
end end
end end
# Delete dangling IDs
db.exec "delete from ids where id in " \ db.exec "delete from ids where id in " \
"(#{trash_ids.map { |i| "'#{i}'" }.join ","})" "(#{trash_ids.map { |i| "'#{i}'" }.join ","})"
Logger.debug "#{trash_ids.size} dangling IDs deleted" \ Logger.debug "#{trash_ids.size} dangling entry IDs deleted" \
if trash_ids.size > 0 if trash_ids.size > 0
# Delete dangling thumbnails # Delete dangling title IDs
trash_thumbnails_count = db.query_one "select count(*) from " \ trash_titles = [] of String
"thumbnails where id not in " \ db.query "select path, id from titles" do |rs|
"(select id from ids)", as: Int32 rs.each do
if trash_thumbnails_count > 0 path = rs.read String
db.exec "delete from thumbnails where id not in (select id from ids)" trash_titles << rs.read String unless Dir.exists? path
Logger.info "#{trash_thumbnails_count} dangling thumbnails deleted" end
end end
# Delete dangling tags db.exec "delete from titles where id in " \
trash_tags_count = db.query_one "select count(*) from tags " \ "(#{trash_titles.map { |i| "'#{i}'" }.join ","})"
"where id not in " \ Logger.debug "#{trash_titles.size} dangling title IDs deleted" \
"(select id from ids)", as: Int32 if trash_titles.size > 0
if trash_tags_count > 0
db.exec "delete from tags where id not in (select id from ids)"
Logger.info "#{trash_tags_count} dangling tags deleted"
end
end end
Logger.info "DB optimization finished" Logger.info "DB optimization finished"
end end