mirror of
https://github.com/nkanaev/yarr.git
synced 2026-06-28 11:05:16 +00:00
121 lines
3.1 KiB
Go
121 lines
3.1 KiB
Go
package postgres
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"log"
|
|
)
|
|
|
|
var migrations = []func(*sql.Tx) error{
|
|
m01_initial,
|
|
}
|
|
|
|
var maxVersion = int64(len(migrations))
|
|
|
|
func migrate(db *sql.DB) error {
|
|
if _, err := db.Exec(
|
|
`create table if not exists schema_version (version bigint primary key)`,
|
|
); err != nil {
|
|
return fmt.Errorf("create schema_version table: %w", err)
|
|
}
|
|
|
|
var version int64
|
|
err := db.QueryRow(
|
|
`select coalesce(max(version), 0) from schema_version`,
|
|
).Scan(&version)
|
|
if err != nil {
|
|
return fmt.Errorf("read schema version: %w", err)
|
|
}
|
|
|
|
if version >= maxVersion {
|
|
return nil
|
|
}
|
|
|
|
log.Printf("db version is %d. migrating to %d", version, maxVersion)
|
|
|
|
for v := version + 1; v <= maxVersion; v++ {
|
|
log.Printf("[migration:%d] starting", v)
|
|
|
|
tx, err := db.Begin()
|
|
if err != nil {
|
|
return fmt.Errorf("migration %d begin tx: %w", v, err)
|
|
}
|
|
|
|
if err := migrations[v-1](tx); err != nil {
|
|
tx.Rollback()
|
|
return fmt.Errorf("migration %d: %w", v, err)
|
|
}
|
|
|
|
if _, err := tx.Exec(
|
|
`insert into schema_version (version) values ($1)
|
|
on conflict do nothing`, v,
|
|
); err != nil {
|
|
tx.Rollback()
|
|
return fmt.Errorf("migration %d record version: %w", v, err)
|
|
}
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
return fmt.Errorf("migration %d commit: %w", v, err)
|
|
}
|
|
|
|
log.Printf("[migration:%d] done", v)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func m01_initial(tx *sql.Tx) error {
|
|
_, err := tx.Exec(`
|
|
create table if not exists folders (
|
|
id bigserial primary key,
|
|
title text not null,
|
|
is_expanded boolean not null default false
|
|
);
|
|
create unique index if not exists idx_folder_title on folders(title);
|
|
|
|
create table if not exists feeds (
|
|
id bigserial primary key,
|
|
folder_id bigint references folders(id) on delete set null,
|
|
title text not null,
|
|
description text,
|
|
link text,
|
|
feed_link text not null,
|
|
icon bytea
|
|
);
|
|
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 table if not exists items (
|
|
id bigserial primary key,
|
|
guid text not null,
|
|
feed_id bigint not null references feeds(id) on delete cascade,
|
|
title text,
|
|
link text,
|
|
content text,
|
|
date timestamptz,
|
|
date_arrived timestamptz,
|
|
last_arrived timestamptz,
|
|
status integer,
|
|
media_links jsonb,
|
|
search tsvector
|
|
);
|
|
create index if not exists idx_item_feed_id on items(feed_id);
|
|
create index if not exists idx_item__date_id_status on items(date, id, status);
|
|
create unique index if not exists idx_item_guid on items(feed_id, guid);
|
|
create index if not exists idx_item_search on items using gin(search);
|
|
|
|
create table if not exists settings (
|
|
key text primary key,
|
|
val jsonb
|
|
);
|
|
|
|
create table if not exists feed_states (
|
|
feed_id bigint primary key references feeds(id) on delete cascade,
|
|
last_refreshed timestamptz not null default '1970-01-01 00:00:00+00',
|
|
last_error text not null default '',
|
|
http_lmod text not null default '',
|
|
http_etag text not null default ''
|
|
);
|
|
`)
|
|
return err
|
|
}
|