2019-02-28 20:49:04 +00:00
|
|
|
// 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.
|
2019-02-19 23:56:41 +00:00
|
|
|
|
|
|
|
package db
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
2019-09-23 23:46:20 +00:00
|
|
|
"runtime/debug"
|
2019-02-19 23:56:41 +00:00
|
|
|
|
|
|
|
"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.
|
2019-09-23 23:46:20 +00:00
|
|
|
func (db *DB) Update(fn func(Execer, Binder) error) (err error) {
|
2019-02-19 23:56:41 +00:00
|
|
|
db.lock.Lock()
|
|
|
|
defer db.lock.Unlock()
|
|
|
|
|
|
|
|
tx, err := db.conn.Begin()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-09-23 23:46:20 +00:00
|
|
|
defer func() {
|
|
|
|
if p := recover(); p != nil {
|
|
|
|
err = tx.Rollback()
|
|
|
|
debug.PrintStack()
|
|
|
|
} else if err != nil {
|
|
|
|
tx.Rollback()
|
|
|
|
} else {
|
|
|
|
err = tx.Commit()
|
|
|
|
}
|
|
|
|
}()
|
2019-02-19 23:56:41 +00:00
|
|
|
|
2019-09-23 23:46:20 +00:00
|
|
|
err = fn(tx, db.conn)
|
|
|
|
return err
|
2019-02-19 23:56:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Driver returns the name of the SQL driver.
|
|
|
|
func (db *DB) Driver() Driver {
|
|
|
|
return db.driver
|
|
|
|
}
|
|
|
|
|
2019-04-16 03:05:41 +00:00
|
|
|
// Close closes the database connection.
|
2019-02-19 23:56:41 +00:00
|
|
|
func (db *DB) Close() error {
|
|
|
|
return db.conn.Close()
|
|
|
|
}
|