github.com/leg100/ots@v0.0.7-0.20210919080622-034055ced4bd/sqlite/sqlite.go (about)

     1  /*
     2  Package sqlite implements persistent storage using the sqlite database.
     3  */
     4  package sqlite
     5  
     6  import (
     7  	"github.com/leg100/go-tfe"
     8  	gormzerolog "github.com/leg100/gorm-zerolog"
     9  	"github.com/leg100/ots"
    10  	"github.com/rs/zerolog"
    11  	driver "gorm.io/driver/sqlite"
    12  	"gorm.io/gorm"
    13  )
    14  
    15  var models = []interface{}{
    16  	&Run{},
    17  	&Apply{},
    18  	&Plan{},
    19  	&ConfigurationVersion{},
    20  	&Organization{},
    21  	&StateVersion{},
    22  	&StateVersionOutput{},
    23  	&Workspace{},
    24  }
    25  
    26  type Option func(*gorm.Config)
    27  
    28  func WithZeroLogger(logger *zerolog.Logger) Option {
    29  	return func(cfg *gorm.Config) {
    30  		cfg.Logger = &gormzerolog.Logger{Zlog: *logger}
    31  	}
    32  }
    33  
    34  func New(path string, opts ...Option) (*gorm.DB, error) {
    35  	cfg := &gorm.Config{}
    36  	for _, o := range opts {
    37  		o(cfg)
    38  	}
    39  
    40  	db, err := gorm.Open(driver.Open(path), cfg)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	// Avoid "database is locked" errors:
    46  	// https://github.com/mattn/go-sqlite3/issues/274
    47  	sqlDB, err := db.DB()
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	sqlDB.SetMaxOpenConns(1)
    52  
    53  	// Enable WAL. SQLite performs better with the WAL because it allows
    54  	// multiple readers to operate while data is being written.
    55  	db.Exec(`PRAGMA journal_mode = wal;`)
    56  
    57  	if err := db.AutoMigrate(models...); err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	return db, nil
    62  }
    63  
    64  // Gorm scopes: https://gorm.io/docs/advanced_query.html#Scopes
    65  
    66  func paginate(opts tfe.ListOptions) func(*gorm.DB) *gorm.DB {
    67  	return func(db *gorm.DB) *gorm.DB {
    68  		ots.SanitizeListOptions(&opts)
    69  
    70  		offset := (opts.PageNumber - 1) * opts.PageSize
    71  
    72  		return db.Offset(offset).Limit(opts.PageSize)
    73  	}
    74  }