// 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" "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) error { db.lock.Lock() defer db.lock.Unlock() tx, err := db.conn.Begin() if err != nil { return err } err = fn(tx, db.conn) if err != nil { tx.Rollback() return err } return tx.Commit() } // 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() }