/// This package is in charge of connecting to the DB and migrations package db import ( "context" "database/sql" "errors" "fmt" _ "github.com/mattn/go-sqlite3" ) var __version = 1 type DbCtx struct { db *sql.DB version int } func initVersion(tx *sql.Tx) (int, error) { var version int // Check the version if err := tx.QueryRow("PRAGMA user_version").Scan(&version); err != nil { tx.Rollback() return 0, fmt.Errorf("Could not select user_version. %w", err) } if version == 0 { _, err := tx.Exec(fmt.Sprintf("PRAGMA user_version=%d", __version)) if err != nil { tx.Rollback() return 0, fmt.Errorf("Could not update pragma version. %w", err) } version = __version } else if version != __version { tx.Rollback() return 0, errors.New(fmt.Sprintf("Wrong version. Expected %d got %d", __version, version)) } return version, nil } func migration0(tx *sql.Tx) error { // Optionally add the version table if _, err := tx.Exec(` create table if not exists eng_log_version (id integer not null); `); err != nil { tx.Rollback() return fmt.Errorf("Could not create eng_log_version. %w", err) } // Optionally add the log table if _, err := tx.Exec(` create table if not exists log (id integer not null primary key, title string) `); err != nil { tx.Rollback() return fmt.Errorf("Could not create log. %w", err) } return nil } func initMigrations(tx *sql.Tx, start_from_versiono int) error { var migrations = []func(*sql.Tx) error{migration0} for migration_idx, migration := range migrations { // Version is 1 indexed, while the migration_idx is 0 indexed var migration_num = migration_idx + 1 if migration_num < start_from_versiono { continue } err := migration(tx) if err != nil { tx.Rollback() return fmt.Errorf("Failed migration %d. %w", migration_num, err) } } return nil } func Init(db_location string) (*DbCtx, error) { db, err := sql.Open("sqlite3", db_location) if err != nil { return nil, fmt.Errorf("Could not connect to DB. %w", err) } if err := db.Ping(); err != nil { return nil, fmt.Errorf("Could not ping DB. %w", err) } ctx := context.Background() tx, err := db.BeginTx(ctx, nil) if err != nil { return nil, err } version, err := initVersion(tx) if err != nil { return nil, err } err = initMigrations(tx, version) if err != nil { return nil, err } tx.Commit() return &DbCtx{db, version}, nil }