harness-drone/store/shared/db/db.go
2019-09-23 16:46:20 -07:00

134 lines
3.3 KiB
Go

// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package db
import (
"database/sql"
"runtime/debug"
"github.com/jmoiron/sqlx"
)
// Driver defines the database driver.
type Driver int
// Database driver enums.
const (
Sqlite = iota + 1
Mysql
Postgres
)
type (
// A Scanner represents an object that can be scanned
// for values.
Scanner interface {
Scan(dest ...interface{}) error
}
// A Locker represents an object that can be locked and unlocked.
Locker interface {
Lock()
Unlock()
RLock()
RUnlock()
}
// Binder interface defines database field bindings.
Binder interface {
BindNamed(query string, arg interface{}) (string, []interface{}, error)
}
// Queryer interface defines a set of methods for
// querying the database.
Queryer interface {
Query(query string, args ...interface{}) (*sql.Rows, error)
QueryRow(query string, args ...interface{}) *sql.Row
}
// Execer interface defines a set of methods for executing
// read and write commands against the database.
Execer interface {
Queryer
Exec(query string, args ...interface{}) (sql.Result, error)
}
// DB is a pool of zero or more underlying connections to
// the drone database.
DB struct {
conn *sqlx.DB
lock Locker
driver Driver
}
)
// View executes a function within the context of a managed read-only
// transaction. Any error that is returned from the function is returned
// from the View() method.
func (db *DB) View(fn func(Queryer, Binder) error) error {
db.lock.RLock()
err := fn(db.conn, db.conn)
db.lock.RUnlock()
return err
}
// Lock obtains a write lock to the database (sqlite only) and executes
// a function. Any error that is returned from the function is returned
// from the Lock() method.
func (db *DB) Lock(fn func(Execer, Binder) error) error {
db.lock.Lock()
err := fn(db.conn, db.conn)
db.lock.Unlock()
return err
}
// Update executes a function within the context of a read-write managed
// transaction. If no error is returned from the function then the
// transaction is committed. If an error is returned then the entire
// transaction is rolled back. Any error that is returned from the function
// or returned from the commit is returned from the Update() method.
func (db *DB) Update(fn func(Execer, Binder) error) (err error) {
db.lock.Lock()
defer db.lock.Unlock()
tx, err := db.conn.Begin()
if err != nil {
return err
}
defer func() {
if p := recover(); p != nil {
err = tx.Rollback()
debug.PrintStack()
} else if err != nil {
tx.Rollback()
} else {
err = tx.Commit()
}
}()
err = fn(tx, db.conn)
return err
}
// Driver returns the name of the SQL driver.
func (db *DB) Driver() Driver {
return db.driver
}
// Close closes the database connection.
func (db *DB) Close() error {
return db.conn.Close()
}