From c806ef393132a858084882e86e3c97eb16e04d2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Nieto?= <jose.carlos@menteslibres.net> Date: Mon, 18 Jul 2016 20:15:56 -0500 Subject: [PATCH] Move SQL functions to the sql.go file. --- db.go | 29 +----------- sql.go | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++ wrapper.go | 61 ++---------------------- 3 files changed, 141 insertions(+), 84 deletions(-) create mode 100644 sql.go diff --git a/db.go b/db.go index 36104d40..bb6d8f5e 100644 --- a/db.go +++ b/db.go @@ -395,7 +395,7 @@ type Database interface { ClearCache() } -// Tx represents transactions that can be either committed or rolled back. +// Tx has methods for transactions that can be either committed or rolled back. type Tx interface { // Rollback discards all the instructions on the current transaction. Rollback() error @@ -509,33 +509,6 @@ type ConnectionURL interface { String() string } -// SQLDatabase represents a Database which is capable of both creating -// transactions and use SQL builder methods. -type SQLDatabase interface { - Database - SQLBuilder - - // NewTx returns a new session that lives within a transaction. This session - // is completely independent from its parent. - NewTx() (SQLTx, error) - - // Tx creates a new transaction that is passed as context to the fn function. - // The fn function defines a transaction operation. If the fn function - // returns nil, the transaction is commited, otherwise the transaction is - // rolled back. The transaction session is closed after the function exists, - // regardless of the error value returned by fn. - Tx(fn func(sess SQLTx) error) error -} - -// SQLTx represents transaction on a SQL database. Transactions can only accept -// intructions until being commited or rolled back, they become useless -// afterwards and are automatically closed. -type SQLTx interface { - Database - SQLBuilder - Tx -} - // EnvEnableDebug can be used by adapters to determine if the user has enabled // debugging. // diff --git a/sql.go b/sql.go new file mode 100644 index 00000000..5e987a6d --- /dev/null +++ b/sql.go @@ -0,0 +1,135 @@ +// Copyright (c) 2012-present The upper.io/db authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +package db + +import ( + "database/sql" + "fmt" + "sync" +) + +var ( + sqlAdapters map[string]*SQLAdapterFuncMap + sqlAdaptersMu sync.RWMutex +) + +func init() { + sqlAdapters = make(map[string]*SQLAdapterFuncMap) + adapters = make(map[string]*AdapterFuncMap) +} + +// SQLCommon holds common methods for SQL databases. +type SQLCommon interface { + Database + SQLBuilder +} + +// SQLTx represents transaction on a SQL database. Transactions can only accept +// intructions until being commited or rolled back, they become useless +// afterwards and are automatically closed. +type SQLTx interface { + SQLCommon + Tx +} + +// SQLDatabase represents a Database which is capable of both creating +// transactions and use SQL builder methods. +type SQLDatabase interface { + SQLCommon + + // NewTx returns a new session that lives within a transaction. This session + // is completely independent from its parent. + NewTx() (SQLTx, error) + + // Tx creates a new transaction that is passed as context to the fn function. + // The fn function defines a transaction operation. If the fn function + // returns nil, the transaction is commited, otherwise the transaction is + // rolled back. The transaction session is closed after the function exists, + // regardless of the error value returned by fn. + Tx(fn func(sess SQLTx) error) error +} + +type SQLAdapterFuncMap struct { + New func(sqlDB *sql.DB) (SQLDatabase, error) + NewTx func(sqlTx *sql.Tx) (SQLTx, error) + Open func(settings ConnectionURL) (SQLDatabase, error) +} + +// RegisterSQLAdapter registers a SQL database adapter. This function must be +// called from adapter packages upon initialization. RegisterSQLAdapter calls +// RegisterAdapter automatically. +func RegisterSQLAdapter(name string, adapter *SQLAdapterFuncMap) { + sqlAdaptersMu.Lock() + defer sqlAdaptersMu.Unlock() + + if name == "" { + panic(`Missing adapter name`) + } + if _, ok := sqlAdapters[name]; ok { + panic(`db.RegisterSQLAdapter() called twice for adapter: ` + name) + } + sqlAdapters[name] = adapter + + RegisterAdapter(name, &AdapterFuncMap{ + Open: func(settings ConnectionURL) (Database, error) { + return adapter.Open(settings) + }, + }) +} + +// SQLAdapter returns SQL database functions. +func SQLAdapter(name string) SQLAdapterFuncMap { + sqlAdaptersMu.RLock() + defer sqlAdaptersMu.RUnlock() + + if fn, ok := sqlAdapters[name]; ok { + return *fn + } + return missingSQLAdapter(name) +} + +func SQLOpen(adapter string, settings ConnectionURL) (SQLDatabase, error) { + return SQLAdapter(adapter).Open(settings) +} + +func SQLNew(adapter string, sqlDB *sql.DB) (SQLDatabase, error) { + return SQLAdapter(adapter).New(sqlDB) +} + +func SQLNewTx(adapter string, sqlTx *sql.Tx) (SQLTx, error) { + return SQLAdapter(adapter).NewTx(sqlTx) +} + +func missingSQLAdapter(name string) SQLAdapterFuncMap { + err := fmt.Errorf("upper: Missing SQL adapter %q, forgot to import?", name) + return SQLAdapterFuncMap{ + New: func(*sql.DB) (SQLDatabase, error) { + return nil, err + }, + NewTx: func(*sql.Tx) (SQLTx, error) { + return nil, err + }, + Open: func(ConnectionURL) (SQLDatabase, error) { + return nil, err + }, + } +} diff --git a/wrapper.go b/wrapper.go index 8fad1c0e..009ec2f5 100644 --- a/wrapper.go +++ b/wrapper.go @@ -22,17 +22,13 @@ package db import ( - "database/sql" "fmt" "sync" ) var ( - sqlAdapters map[string]*SQLAdapterFuncMap - adapters map[string]*AdapterFuncMap - - sqlAdaptersMu sync.RWMutex - adaptersMu sync.RWMutex + adapters map[string]*AdapterFuncMap + adaptersMu sync.RWMutex ) func init() { @@ -44,12 +40,8 @@ type AdapterFuncMap struct { Open func(settings ConnectionURL) (Database, error) } -type SQLAdapterFuncMap struct { - New func(sqlDB *sql.DB) (SQLDatabase, error) - NewTx func(sqlTx *sql.Tx) (SQLTx, error) - Open func(settings ConnectionURL) (SQLDatabase, error) -} - +// RegisterAdapter registers a generic Database adapter. This function must be +// called from adapter packages upon initialization. func RegisterAdapter(name string, adapter *AdapterFuncMap) { adaptersMu.Lock() defer adaptersMu.Unlock() @@ -63,25 +55,7 @@ func RegisterAdapter(name string, adapter *AdapterFuncMap) { adapters[name] = adapter } -func RegisterSQLAdapter(name string, adapter *SQLAdapterFuncMap) { - sqlAdaptersMu.Lock() - defer sqlAdaptersMu.Unlock() - - if name == "" { - panic(`Missing adapter name`) - } - if _, ok := sqlAdapters[name]; ok { - panic(`db.RegisterSQLAdapter() called twice for adapter: ` + name) - } - sqlAdapters[name] = adapter - - RegisterAdapter(name, &AdapterFuncMap{ - Open: func(settings ConnectionURL) (Database, error) { - return adapter.Open(settings) - }, - }) -} - +// Adapter returns a method map from the given adapter. func Adapter(name string) AdapterFuncMap { adaptersMu.RLock() defer adaptersMu.RUnlock() @@ -92,16 +66,6 @@ func Adapter(name string) AdapterFuncMap { return missingAdapter(name) } -func SQLAdapter(name string) SQLAdapterFuncMap { - sqlAdaptersMu.RLock() - defer sqlAdaptersMu.RUnlock() - - if fn, ok := sqlAdapters[name]; ok { - return *fn - } - return missingSQLAdapter(name) -} - func missingAdapter(name string) AdapterFuncMap { err := fmt.Errorf("upper: Missing adapter %q, forgot to import?", name) return AdapterFuncMap{ @@ -111,21 +75,6 @@ func missingAdapter(name string) AdapterFuncMap { } } -func missingSQLAdapter(name string) SQLAdapterFuncMap { - err := fmt.Errorf("upper: Missing SQL adapter %q, forgot to import?", name) - return SQLAdapterFuncMap{ - New: func(*sql.DB) (SQLDatabase, error) { - return nil, err - }, - NewTx: func(*sql.Tx) (SQLTx, error) { - return nil, err - }, - Open: func(ConnectionURL) (SQLDatabase, error) { - return nil, err - }, - } -} - // Open attempts to open a database. Returns a generic Database instance on // success. func Open(adapter string, settings ConnectionURL) (Database, error) { -- GitLab