/server/db/db.go
https://github.com/sentriz/gonic · Go · 155 lines · 132 code · 15 blank · 8 comment · 14 complexity · abbf4ddf8ced688f9a91d7adcd3debcf MD5 · raw file
- package db
- import (
- "fmt"
- "log"
- "net/url"
- "os"
- "github.com/gorilla/securecookie"
- "github.com/jinzhu/gorm"
- "gopkg.in/gormigrate.v1"
- )
- // wrapMigrations wraps a list of migrations to add logging and transactions
- func wrapMigrations(migrs ...gormigrate.Migration) []*gormigrate.Migration {
- log := func(i int, mig gormigrate.MigrateFunc, name string) gormigrate.MigrateFunc {
- return func(db *gorm.DB) error {
- // print that we're on the ith out of n migrations
- defer log.Printf("migration (%d/%d) '%s' finished", i+1, len(migrs), name)
- return db.Transaction(mig)
- }
- }
- ret := make([]*gormigrate.Migration, 0, len(migrs))
- for i, mig := range migrs {
- ret = append(ret, &gormigrate.Migration{
- ID: mig.ID,
- Rollback: mig.Rollback,
- Migrate: log(i, mig.Migrate, mig.ID),
- })
- }
- return ret
- }
- func defaultOptions() url.Values {
- return url.Values{
- // with this, multiple connections share a single data and schema cache.
- // see https://www.sqlite.org/sharedcache.html
- "cache": {"shared"},
- // with this, the db sleeps for a little while when locked. can prevent
- // a SQLITE_BUSY. see https://www.sqlite.org/c3ref/busy_timeout.html
- "_busy_timeout": {"30000"},
- "_journal_mode": {"WAL"},
- "_foreign_keys": {"true"},
- }
- }
- type DB struct {
- *gorm.DB
- }
- func New(path string) (*DB, error) {
- // https://github.com/mattn/go-sqlite3#connection-string
- url := url.URL{
- Scheme: "file",
- Opaque: path,
- }
- url.RawQuery = defaultOptions().Encode()
- db, err := gorm.Open("sqlite3", url.String())
- if err != nil {
- return nil, fmt.Errorf("with gorm: %w", err)
- }
- db.SetLogger(log.New(os.Stdout, "gorm ", 0))
- db.DB().SetMaxOpenConns(1)
- migrOptions := &gormigrate.Options{
- TableName: "migrations",
- IDColumnName: "id",
- IDColumnSize: 255,
- UseTransaction: false,
- }
- migr := gormigrate.New(db, migrOptions, wrapMigrations(
- migrateInitSchema(),
- migrateCreateInitUser(),
- migrateMergePlaylist(),
- migrateCreateTranscode(),
- migrateAddGenre(),
- migrateUpdateTranscodePrefIDX(),
- migrateAddAlbumIDX(),
- ))
- if err = migr.Migrate(); err != nil {
- return nil, fmt.Errorf("migrating to latest version: %w", err)
- }
- return &DB{DB: db}, nil
- }
- func NewMock() (*DB, error) {
- return New(":memory:")
- }
- func (db *DB) GetSetting(key string) string {
- setting := &Setting{}
- db.
- Where("key=?", key).
- First(setting)
- return setting.Value
- }
- func (db *DB) SetSetting(key, value string) {
- db.
- Where(Setting{Key: key}).
- Assign(Setting{Value: value}).
- FirstOrCreate(&Setting{})
- }
- func (db *DB) GetOrCreateKey(key string) string {
- value := db.GetSetting(key)
- if value == "" {
- value = string(securecookie.GenerateRandomKey(32))
- db.SetSetting(key, value)
- }
- return value
- }
- func (db *DB) GetUserByID(id int) *User {
- user := &User{}
- err := db.
- Where("id=?", id).
- First(user).
- Error
- if gorm.IsRecordNotFoundError(err) {
- return nil
- }
- return user
- }
- func (db *DB) GetUserByName(name string) *User {
- user := &User{}
- err := db.
- Where("name=?", name).
- First(user).
- Error
- if gorm.IsRecordNotFoundError(err) {
- return nil
- }
- return user
- }
- type ChunkFunc func(*gorm.DB, []int64) error
- func (db *DB) TransactionChunked(data []int64, cb ChunkFunc) error {
- // https://sqlite.org/limits.html
- const size = 999
- return db.Transaction(func(tx *gorm.DB) error {
- for i := 0; i < len(data); i += size {
- end := i + size
- if end > len(data) {
- end = len(data)
- }
- if err := cb(tx, data[i:end]); err != nil {
- return err
- }
- }
- return nil
- })
- }