refactor: update scanner, scanner tests, mockfs

closes #165
closes #163
This commit is contained in:
sentriz
2021-11-03 23:05:08 +00:00
parent b07b9a8be6
commit fa587fc7de
64 changed files with 3469 additions and 2373 deletions

View File

@@ -1,39 +1,19 @@
package db
import (
"errors"
"fmt"
"log"
"net/url"
"os"
"strings"
"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 {
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
@@ -46,17 +26,23 @@ func defaultOptions() url.Values {
}
}
func mockOptions() url.Values {
return url.Values{
"_foreign_keys": {"true"},
}
}
type DB struct {
*gorm.DB
}
func New(path string) (*DB, error) {
func New(path string, options url.Values) (*DB, error) {
// https://github.com/mattn/go-sqlite3#connection-string
url := url.URL{
Scheme: "file",
Opaque: path,
}
url.RawQuery = defaultOptions().Encode()
url.RawQuery = options.Encode()
db, err := gorm.Open("sqlite3", url.String())
if err != nil {
return nil, fmt.Errorf("with gorm: %w", err)
@@ -91,34 +77,29 @@ func New(path string) (*DB, error) {
}
func NewMock() (*DB, error) {
return New(":memory:")
return New(":memory:", mockOptions())
}
func (db *DB) GetSetting(key string) string {
func (db *DB) GetSetting(key string) (string, error) {
setting := &Setting{}
db.
Where("key=?", key).
First(setting)
return setting.Value
if err := db.Where("key=?", key).First(setting).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return "", err
}
return setting.Value, nil
}
func (db *DB) SetSetting(key, value string) {
db.
func (db *DB) SetSetting(key, value string) error {
return 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
FirstOrCreate(&Setting{}).
Error
}
func (db *DB) InsertBulkLeftMany(table string, head []string, left int, col []int) error {
if len(col) == 0 {
return nil
}
var rows []string
var values []interface{}
for _, c := range col {
@@ -139,7 +120,7 @@ func (db *DB) GetUserByID(id int) *User {
Where("id=?", id).
First(user).
Error
if gorm.IsRecordNotFoundError(err) {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return user
@@ -151,7 +132,7 @@ func (db *DB) GetUserByName(name string) *User {
Where("name=?", name).
First(user).
Error
if gorm.IsRecordNotFoundError(err) {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return user
@@ -164,6 +145,9 @@ func (db *DB) Begin() *DB {
type ChunkFunc func(*gorm.DB, []int64) error
func (db *DB) TransactionChunked(data []int64, cb ChunkFunc) error {
if len(data) == 0 {
return nil
}
// https://sqlite.org/limits.html
const size = 999
return db.Transaction(func(tx *gorm.DB) error {

View File

@@ -1,16 +1,16 @@
package db
import (
"io/ioutil"
"log"
"math/rand"
"os"
"testing"
_ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/matryer/is"
)
var testDB *DB
func randKey() string {
letters := []rune("abcdef0123456789")
b := make([]rune, 16)
@@ -22,27 +22,31 @@ func randKey() string {
func TestGetSetting(t *testing.T) {
key := randKey()
// new key
expected := "hello"
testDB.SetSetting(key, expected)
actual := testDB.GetSetting(key)
if actual != expected {
t.Errorf("expected %q, got %q", expected, actual)
value := "howdy"
is := is.New(t)
testDB, err := NewMock()
if err != nil {
t.Fatalf("error creating db: %v", err)
}
// existing key
expected = "howdy"
testDB.SetSetting(key, expected)
actual = testDB.GetSetting(key)
if actual != expected {
t.Errorf("expected %q, got %q", expected, actual)
if err := testDB.Migrate(MigrationContext{}); err != nil {
t.Fatalf("error migrating db: %v", err)
}
is.NoErr(testDB.SetSetting(key, value))
actual, err := testDB.GetSetting(key)
is.NoErr(err)
is.Equal(actual, value)
is.NoErr(testDB.SetSetting(key, value))
actual, err = testDB.GetSetting(key)
is.NoErr(err)
is.Equal(actual, value)
}
func TestMain(m *testing.M) {
var err error
testDB, err = NewMock()
if err != nil {
log.Fatalf("error opening database: %v\n", err)
}
log.SetOutput(ioutil.Discard)
os.Exit(m.Run())
}

View File

@@ -1,6 +1,7 @@
package db
import (
"errors"
"fmt"
"github.com/jinzhu/gorm"
@@ -31,20 +32,14 @@ func migrateInitSchema() gormigrate.Migration {
}
}
func migrateCreateInitUser() gormigrate.Migration {
return gormigrate.Migration{
ID: "202002192019",
Migrate: func(tx *gorm.DB) error {
const (
initUsername = "admin"
initPassword = "admin"
)
err := tx.
Where("name=?", initUsername).
First(&User{}).
Error
if !gorm.IsRecordNotFoundError(err) {
return nil
func construct(ctx MigrationContext, id string, f func(*gorm.DB, MigrationContext) error) *gormigrate.Migration {
return &gormigrate.Migration{
ID: id,
Migrate: func(db *gorm.DB) error {
tx := db.Begin()
defer tx.Commit()
if err := f(tx, ctx); err != nil {
return fmt.Errorf("%q: %w", id, err)
}
return tx.Create(&User{

View File

@@ -88,7 +88,7 @@ type Track struct {
Artist *Artist
ArtistID int `gorm:"not null" sql:"default: null; type:int REFERENCES artists(id) ON DELETE CASCADE"`
Genres []*Genre `gorm:"many2many:track_genres"`
Size int `gorm:"not null" sql:"default: null"`
Size int `sql:"default: null"`
Length int `sql:"default: null"`
Bitrate int `sql:"default: null"`
TagTitle string `sql:"default: null"`