From fa2b97242dcd00ece6174b87043769651153fe82 Mon Sep 17 00:00:00 2001 From: Nazar Kanaev Date: Wed, 10 Mar 2021 21:58:00 +0000 Subject: [PATCH] storage fixes --- src/server/crawler.go | 4 +-- src/storage/item.go | 2 +- src/storage/migration.go | 77 +++++++++++++++++++++++++--------------- 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/src/server/crawler.go b/src/server/crawler.go index 3351027..946f798 100644 --- a/src/server/crawler.go +++ b/src/server/crawler.go @@ -238,11 +238,11 @@ func convertItems(items []*gofeed.Item, feed storage.Feed) []storage.Item { if item.Author != nil { author = item.Author.Name } - podcastUrl := "" + var podcastUrl *string if item.Enclosures != nil { for _, enclosure := range item.Enclosures { if strings.ToLower(enclosure.Type) == "audio/mpeg" { - podcastUrl = enclosure.URL + podcastUrl = &enclosure.URL } } } diff --git a/src/storage/item.go b/src/storage/item.go index 4a1eaab..b37a328 100644 --- a/src/storage/item.go +++ b/src/storage/item.go @@ -55,7 +55,7 @@ type Item struct { DateUpdated *time.Time `json:"date_updated"` Status ItemStatus `json:"status"` Image string `json:"image"` - PodcastURL string `json:"podcast_url"` + PodcastURL *string `json:"podcast_url"` } type ItemFilter struct { diff --git a/src/storage/migration.go b/src/storage/migration.go index 63ecdf9..67ecbe2 100644 --- a/src/storage/migration.go +++ b/src/storage/migration.go @@ -26,34 +26,58 @@ func migrate(db *sql.DB, log *log.Logger) error { log.Printf("db version is %d. migrating to %d", version, maxVersion) for v := version + 1; v <= maxVersion; v++ { - migratefunc := migrations[v - 1] - var tx *sql.Tx - var err error + // Migrations altering schema using a sequence of steps due to SQLite limitations. + // Must come with `pragma foreign_key_check` at the end. See: + // "Making Other Kinds Of Table Schema Changes" + // https://www.sqlite.org/lang_altertable.html + trickyAlteration := (v == 3) log.Printf("[migration:%d] starting", v) - if tx, err = db.Begin(); err != nil { - log.Printf("[migration:%d] failed to start transaction", v) - return err - } - if err = migratefunc(tx); err != nil { - log.Printf("[migration:%d] failed to migrate", v) - tx.Rollback() - return err - } - if _, err = tx.Exec(fmt.Sprintf("pragma user_version = %d", v)); err != nil { - log.Printf("[migration:%d] failed to bump version", v) - tx.Rollback() - return err - } - if err = tx.Commit(); err != nil { - log.Printf("[migration:%d] failed to commit changes", v) + + if trickyAlteration { + db.Exec("pragma foreign_keys=off;") + } + + err := migrateVersion(v, db) + + if trickyAlteration { + db.Exec("pragma foreign_keys=on;") + } + + if err != nil { return err } + log.Printf("[migration:%d] done", v) } return nil } +func migrateVersion(v int64, db *sql.DB) error { + var err error + var tx *sql.Tx + migratefunc := migrations[v - 1] + if tx, err = db.Begin(); err != nil { + log.Printf("[migration:%d] failed to start transaction", v) + return err + } + if err = migratefunc(tx); err != nil { + log.Printf("[migration:%d] failed to migrate", v) + tx.Rollback() + return err + } + if _, err = tx.Exec(fmt.Sprintf("pragma user_version = %d", v)); err != nil { + log.Printf("[migration:%d] failed to bump version", v) + tx.Rollback() + return err + } + if err = tx.Commit(); err != nil { + log.Printf("[migration:%d] failed to commit changes", v) + return err + } + return nil +} + func m01_initial(tx *sql.Tx) error { sql := ` create table if not exists folders ( @@ -136,10 +160,7 @@ func m02_feed_states_and_errors(tx *sql.Tx) error { func m03_on_delete_actions(tx *sql.Tx) error { sql := ` - -- 01. disable foreignkey constraint - pragma foreign_keys=off; - - -- 02. create altered tables + -- 01. create altered tables create table if not exists new_feeds ( id integer primary key autoincrement, folder_id references folders(id) on delete set null, @@ -176,25 +197,25 @@ func m03_on_delete_actions(tx *sql.Tx) error { error string ); - -- 03. transfer content into new tables + -- 02. transfer data into new tables insert into new_feeds select * from feeds; insert into new_items select * from items; insert into new_http_states select * from http_states; insert into new_feed_errors select * from feed_errors; - -- 04. drop old tables + -- 03. drop old tables drop table feeds; drop table items; drop table http_states; drop table feed_errors; - -- 05. rename new tables + -- 04. rename new tables alter table new_feeds rename to feeds; alter table new_items rename to items; alter table new_http_states rename to http_states; alter table new_feed_errors rename to feed_errors; - -- 06. reconstruct indexes & triggers + -- 05. reconstruct indexes & triggers create index if not exists idx_feed_folder_id on feeds(folder_id); create unique index if not exists idx_feed_feed_link on feeds(feed_link); create index if not exists idx_item_feed_id on items(feed_id); @@ -205,8 +226,8 @@ func m03_on_delete_actions(tx *sql.Tx) error { delete from search where rowid = old.search_rowid; end; + -- 06. check consistency pragma foreign_key_check; - pragma foreign_keys=on; ` _, err := tx.Exec(sql) return err