1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-09-30 19:22:11 +00:00

feat: multi db support

This commit is contained in:
haras 2025-09-14 08:50:42 +02:00
parent 10b2b36895
commit fe6c000897
25 changed files with 2612 additions and 1433 deletions

View file

@ -7,13 +7,68 @@ import (
"database/sql"
"fmt"
"log/slog"
"strings"
"time"
)
type DBKind int
const (
DBKindPostgres DBKind = iota
DBKindCockroach
DBKindSqlite
)
var dbKindProto = map[DBKind]string{
DBKindPostgres: "postgresql",
DBKindCockroach: "cockroachdb",
DBKindSqlite: "sqlite",
}
var dbKindDriver = map[DBKind]string{
DBKindPostgres: "postgres",
DBKindCockroach: "postgres",
DBKindSqlite: "sqlite",
}
func DetectKind(conn string) (DBKind, error) {
switch {
case strings.HasPrefix(conn, "postgres"),
strings.HasPrefix(conn, "postgresql"):
return DBKindPostgres, nil
case strings.HasPrefix(conn, "cockroach"),
strings.HasPrefix(conn, "cockroachdb"):
return DBKindCockroach, nil
case strings.HasPrefix(conn, "file"),
strings.HasPrefix(conn, "sqlite"):
return DBKindSqlite, nil
default:
return 0, fmt.Errorf("unknown db kind in conn string: %q", conn)
}
}
type Migration func(*sql.Tx) error
var dbKindMigrations = map[DBKind][]Migration{
DBKindPostgres: postgresMigrations,
DBKindCockroach: cockroachMigrations,
DBKindSqlite: sqliteMigrations,
}
var dbKindSchemaVersion = map[DBKind]int{
DBKindPostgres: postgresSchemaVersion,
DBKindCockroach: cockroachSchemaVersion,
DBKindSqlite: sqliteSchemaVersion,
}
// Migrate executes database migrations.
func Migrate(db *sql.DB) error {
func Migrate(kind DBKind, db *sql.DB) error {
var currentVersion int
db.QueryRow(`SELECT version FROM schema_version`).Scan(&currentVersion)
migrations := dbKindMigrations[kind]
schemaVersion := dbKindSchemaVersion[kind]
slog.Info("Running database migrations",
slog.Int("current_version", currentVersion),
slog.Int("latest_version", schemaVersion),
@ -32,14 +87,24 @@ func Migrate(db *sql.DB) error {
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
}
if _, err := tx.Exec(`TRUNCATE schema_version`); err != nil {
tx.Rollback()
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
}
if _, err := tx.Exec(`INSERT INTO schema_version (version) VALUES ($1)`, newVersion); err != nil {
tx.Rollback()
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
if kind == DBKindSqlite {
if _, err := tx.Exec(`DELETE FROM schema_version`); err != nil {
tx.Rollback()
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
}
if _, err := tx.Exec(`INSERT INTO schema_version (version) VALUES (?)`, newVersion); err != nil {
tx.Rollback()
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
}
} else {
if _, err := tx.Exec(`TRUNCATE schema_version`); err != nil {
tx.Rollback()
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
}
if _, err := tx.Exec(`INSERT INTO schema_version (version) VALUES ($1)`, newVersion); err != nil {
tx.Rollback()
return fmt.Errorf("[Migration v%d] %v", newVersion, err)
}
}
if err := tx.Commit(); err != nil {
@ -51,7 +116,9 @@ func Migrate(db *sql.DB) error {
}
// IsSchemaUpToDate checks if the database schema is up to date.
func IsSchemaUpToDate(db *sql.DB) error {
func IsSchemaUpToDate(kind DBKind, db *sql.DB) error {
schemaVersion := dbKindSchemaVersion[kind]
var currentVersion int
db.QueryRow(`SELECT version FROM schema_version`).Scan(&currentVersion)
if currentVersion < schemaVersion {
@ -59,3 +126,25 @@ func IsSchemaUpToDate(db *sql.DB) error {
}
return nil
}
func NewConnectionPool(kind DBKind, dsn string, minConnections, maxConnections int, connectionLifetime time.Duration) (*sql.DB, error) {
driver := dbKindDriver[kind]
// replace cockroachdb protocol with postgres
// we use cockroachdb protocol to detect cockroachdb but go wants postgres
if kind == DBKindCockroach {
split := strings.SplitN(dsn, ":", 2)
dsn = fmt.Sprintf("postgres:%s", split[1])
}
db, err := sql.Open(driver, dsn)
if err != nil {
return nil, err
}
db.SetMaxOpenConns(maxConnections)
db.SetMaxIdleConns(minConnections)
db.SetConnMaxLifetime(connectionLifetime)
return db, nil
}