2013-10-25 14:04:48 +04:00
package gorm
2013-11-16 07:36:30 +04:00
import (
"database/sql"
2014-07-30 16:48:36 +04:00
"errors"
"fmt"
"reflect"
2015-01-20 07:15:24 +03:00
"strings"
2018-08-19 02:09:21 +03:00
"sync"
2016-03-08 16:45:20 +03:00
"time"
2013-11-16 14:01:44 +04:00
)
2013-11-10 18:29:53 +04:00
2016-03-07 09:54:20 +03:00
// DB contains information for current db connection
2013-10-25 14:04:48 +04:00
type DB struct {
2019-04-14 11:41:14 +03:00
sync . RWMutex
2017-02-05 08:31:31 +03:00
Value interface { }
Error error
RowsAffected int64
// single db
2017-03-14 23:32:38 +03:00
db SQLCommon
2017-02-05 08:31:31 +03:00
blockGlobalUpdate bool
2018-12-13 16:04:51 +03:00
logMode logModeValue
2015-02-28 06:48:18 +03:00
logger logger
2017-02-05 08:31:31 +03:00
search * search
2018-09-10 01:26:29 +03:00
values sync . Map
2017-02-05 08:31:31 +03:00
// global db
parent * DB
callbacks * Callback
dialect Dialect
singularTable bool
2013-10-25 14:04:48 +04:00
}
2018-12-13 16:04:51 +03:00
type logModeValue int
const (
defaultLogMode logModeValue = iota
noLogMode
detailedLogMode
)
2016-03-07 16:09:05 +03:00
// Open initialize a new db connection, need to import driver first, e.g:
2016-03-07 09:54:20 +03:00
//
// import _ "github.com/go-sql-driver/mysql"
// func main() {
// db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
// }
2016-03-07 16:09:05 +03:00
// GORM has wrapped some drivers, for easier to remember driver's import path, so you could import the mysql driver with
2016-03-07 09:54:20 +03:00
// import _ "github.com/jinzhu/gorm/dialects/mysql"
2016-03-07 16:09:05 +03:00
// // import _ "github.com/jinzhu/gorm/dialects/postgres"
// // import _ "github.com/jinzhu/gorm/dialects/sqlite"
// // import _ "github.com/jinzhu/gorm/dialects/mssql"
2017-02-05 08:31:31 +03:00
func Open ( dialect string , args ... interface { } ) ( db * DB , err error ) {
2014-11-22 22:24:26 +03:00
if len ( args ) == 0 {
2014-08-05 06:32:15 +04:00
err = errors . New ( "invalid database source" )
2016-10-07 14:42:29 +03:00
return nil , err
}
var source string
2017-03-14 23:32:38 +03:00
var dbSQL SQLCommon
2018-07-27 02:43:09 +03:00
var ownDbSQL bool
2015-02-17 17:55:14 +03:00
2016-10-07 14:42:29 +03:00
switch value := args [ 0 ] . ( type ) {
case string :
var driver = dialect
if len ( args ) == 1 {
source = value
} else if len ( args ) >= 2 {
driver = value
source = args [ 1 ] . ( string )
2015-02-17 17:55:14 +03:00
}
2016-10-07 14:42:29 +03:00
dbSQL , err = sql . Open ( driver , source )
2018-07-27 02:43:09 +03:00
ownDbSQL = true
2017-03-14 23:32:38 +03:00
case SQLCommon :
2016-10-07 14:42:29 +03:00
dbSQL = value
2018-07-27 02:43:09 +03:00
ownDbSQL = false
2018-05-02 17:37:51 +03:00
default :
return nil , fmt . Errorf ( "invalid database source: %v is not a valid type" , value )
2016-10-07 14:42:29 +03:00
}
2014-08-05 06:32:15 +04:00
2017-02-05 08:31:31 +03:00
db = & DB {
db : dbSQL ,
2016-10-07 14:42:29 +03:00
logger : defaultLogger ,
2017-02-05 08:31:31 +03:00
callbacks : DefaultCallback ,
dialect : newDialect ( dialect , dbSQL ) ,
2016-10-07 14:42:29 +03:00
}
2017-02-05 08:31:31 +03:00
db . parent = db
2017-04-06 16:55:36 +03:00
if err != nil {
return
}
// Send a ping to make sure the database connection is alive.
if d , ok := dbSQL . ( * sql . DB ) ; ok {
2018-07-27 02:43:09 +03:00
if err = d . Ping ( ) ; err != nil && ownDbSQL {
2017-04-06 16:55:36 +03:00
d . Close ( )
2015-08-02 02:37:33 +03:00
}
2014-08-05 06:32:15 +04:00
}
2017-02-05 08:31:31 +03:00
return
2016-09-13 02:41:42 +03:00
}
2016-03-07 16:09:05 +03:00
// New clone a new db connection without search conditions
2015-03-04 08:55:39 +03:00
func ( s * DB ) New ( ) * DB {
clone := s . clone ( )
clone . search = nil
clone . Value = nil
return clone
}
2017-03-14 23:32:38 +03:00
type closer interface {
Close ( ) error
}
// Close close current db connection. If database connection is not an io.Closer, returns an error.
2017-02-05 08:31:31 +03:00
func ( s * DB ) Close ( ) error {
2017-03-14 23:32:38 +03:00
if db , ok := s . parent . db . ( closer ) ; ok {
2017-02-05 08:31:31 +03:00
return db . Close ( )
}
return errors . New ( "can't close current db" )
}
// DB get `*sql.DB` from current connection
2017-03-14 23:32:38 +03:00
// If the underlying database connection is not a *sql.DB, returns nil
2017-02-05 08:31:31 +03:00
func ( s * DB ) DB ( ) * sql . DB {
2017-03-14 23:32:38 +03:00
db , _ := s . db . ( * sql . DB )
return db
2015-02-26 07:35:33 +03:00
}
2016-03-07 16:09:05 +03:00
// CommonDB return the underlying `*sql.DB` or `*sql.Tx` instance, mainly intended to allow coexistence with legacy non-GORM code.
2017-03-14 23:32:38 +03:00
func ( s * DB ) CommonDB ( ) SQLCommon {
2014-03-17 14:08:44 +04:00
return s . db
2014-03-16 20:24:32 +04:00
}
2017-02-05 08:31:31 +03:00
// Dialect get dialect
func ( s * DB ) Dialect ( ) Dialect {
2018-07-27 02:35:53 +03:00
return s . dialect
2017-02-05 08:31:31 +03:00
}
2016-03-07 16:09:05 +03:00
// Callback return `Callbacks` container, you could add/change/delete callbacks with it
2016-03-07 09:54:20 +03:00
// db.Callback().Create().Register("update_created_at", updateCreated)
2016-03-07 16:09:05 +03:00
// Refer https://jinzhu.github.io/gorm/development.html#callbacks
2016-01-16 16:55:00 +03:00
func ( s * DB ) Callback ( ) * Callback {
2019-05-02 00:54:39 +03:00
s . parent . callbacks = s . parent . callbacks . clone ( s . logger )
2016-01-16 14:20:52 +03:00
return s . parent . callbacks
2014-01-29 06:25:58 +04:00
}
2016-03-07 09:54:20 +03:00
// SetLogger replace default logger
func ( s * DB ) SetLogger ( log logger ) {
s . logger = log
2013-11-11 05:05:14 +04:00
}
2016-03-07 09:54:20 +03:00
// LogMode set log mode, `true` for detailed logs, `false` for no log, default, will only print error logs
2015-02-17 17:55:14 +03:00
func ( s * DB ) LogMode ( enable bool ) * DB {
if enable {
2018-12-13 16:04:51 +03:00
s . logMode = detailedLogMode
2013-12-17 15:16:03 +04:00
} else {
2018-12-13 16:04:51 +03:00
s . logMode = noLogMode
2013-12-17 15:16:03 +04:00
}
2013-11-16 11:01:31 +04:00
return s
2013-11-16 07:36:30 +04:00
}
2016-11-04 19:41:31 +03:00
// BlockGlobalUpdate if true, generates an error on update/delete without where clause.
// This is to prevent eventual error with empty objects updates/deletions
func ( s * DB ) BlockGlobalUpdate ( enable bool ) * DB {
s . blockGlobalUpdate = enable
return s
}
// HasBlockGlobalUpdate return state of block
func ( s * DB ) HasBlockGlobalUpdate ( ) bool {
return s . blockGlobalUpdate
}
2016-03-07 09:54:20 +03:00
// SingularTable use singular table by default
2015-02-17 17:55:14 +03:00
func ( s * DB ) SingularTable ( enable bool ) {
2019-04-14 10:38:06 +03:00
s . parent . Lock ( )
defer s . parent . Unlock ( )
2015-02-17 17:55:14 +03:00
s . parent . singularTable = enable
2013-11-16 07:36:30 +04:00
}
2017-02-05 08:31:31 +03:00
// NewScope create a scope for current operation
func ( s * DB ) NewScope ( value interface { } ) * Scope {
dbClone := s . clone ( )
dbClone . Value = value
2019-03-10 14:33:49 +03:00
scope := & Scope { db : dbClone , Value : value }
if s . search != nil {
scope . Search = s . search . clone ( )
} else {
scope . Search = & search { }
}
return scope
2017-02-05 08:31:31 +03:00
}
2017-08-02 02:41:43 +03:00
// QueryExpr returns the query as expr object
func ( s * DB ) QueryExpr ( ) * expr {
scope := s . NewScope ( s . Value )
scope . InstanceSet ( "skip_bindvar" , true )
scope . prepareQuerySQL ( )
2017-08-11 18:24:00 +03:00
return Expr ( scope . SQL , scope . SQLVars ... )
2017-08-02 02:41:43 +03:00
}
2018-02-22 07:04:12 +03:00
// SubQuery returns the query as sub query
func ( s * DB ) SubQuery ( ) * expr {
scope := s . NewScope ( s . Value )
scope . InstanceSet ( "skip_bindvar" , true )
scope . prepareQuerySQL ( )
return Expr ( fmt . Sprintf ( "(%v)" , scope . SQL ) , scope . SQLVars ... )
}
2017-01-04 10:53:49 +03:00
// Where return a new relation, filter records with given conditions, accepts `map`, `struct` or `string` as conditions, refer http://jinzhu.github.io/gorm/crud.html#query
2013-11-16 07:36:30 +04:00
func ( s * DB ) Where ( query interface { } , args ... interface { } ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Where ( query , args ... ) . db
2013-11-16 07:36:30 +04:00
}
2016-03-07 16:09:05 +03:00
// Or filter records that match before conditions or this one, similar to `Where`
2013-11-16 07:36:30 +04:00
func ( s * DB ) Or ( query interface { } , args ... interface { } ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Or ( query , args ... ) . db
2013-11-16 07:36:30 +04:00
}
2016-03-07 16:09:05 +03:00
// Not filter records that don't match current conditions, similar to `Where`
2013-11-16 07:36:30 +04:00
func ( s * DB ) Not ( query interface { } , args ... interface { } ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Not ( query , args ... ) . db
2013-11-16 07:36:30 +04:00
}
2016-03-07 09:54:20 +03:00
// Limit specify the number of records to be retrieved
2016-06-21 06:13:33 +03:00
func ( s * DB ) Limit ( limit interface { } ) * DB {
2016-01-18 15:32:52 +03:00
return s . clone ( ) . search . Limit ( limit ) . db
2013-11-16 07:36:30 +04:00
}
2016-03-07 09:54:20 +03:00
// Offset specify the number of records to skip before starting to return the records
2016-06-21 06:13:33 +03:00
func ( s * DB ) Offset ( offset interface { } ) * DB {
2016-01-18 15:32:52 +03:00
return s . clone ( ) . search . Offset ( offset ) . db
2013-11-16 07:36:30 +04:00
}
2016-03-07 16:09:05 +03:00
// Order specify order when retrieve records from database, set reorder to `true` to overwrite defined conditions
2016-06-28 06:15:42 +03:00
// db.Order("name DESC")
// db.Order("name DESC", true) // reorder
// db.Order(gorm.Expr("name = ? DESC", "first")) // sql expression
func ( s * DB ) Order ( value interface { } , reorder ... bool ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Order ( value , reorder ... ) . db
2013-11-11 07:11:49 +04:00
}
2016-03-07 16:09:05 +03:00
// Select specify fields that you want to retrieve from database when querying, by default, will select all fields;
2016-03-07 09:54:20 +03:00
// When creating/updating, specify fields that you want to save to database
2014-11-17 15:12:32 +03:00
func ( s * DB ) Select ( query interface { } , args ... interface { } ) * DB {
2015-03-12 10:50:38 +03:00
return s . clone ( ) . search . Select ( query , args ... ) . db
2013-11-06 17:43:41 +04:00
}
2016-03-07 16:09:05 +03:00
// Omit specify fields that you want to ignore when saving to database for creating, updating
2015-03-12 13:01:27 +03:00
func ( s * DB ) Omit ( columns ... string ) * DB {
return s . clone ( ) . search . Omit ( columns ... ) . db
}
2016-03-07 09:54:20 +03:00
// Group specify the group method on the find
2013-11-17 09:22:09 +04:00
func ( s * DB ) Group ( query string ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Group ( query ) . db
2013-11-17 09:22:09 +04:00
}
2016-03-07 09:54:20 +03:00
// Having specify HAVING conditions for GROUP BY
2017-08-02 02:41:43 +03:00
func ( s * DB ) Having ( query interface { } , values ... interface { } ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Having ( query , values ... ) . db
2013-11-17 09:22:09 +04:00
}
2016-03-07 09:54:20 +03:00
// Joins specify Joins conditions
// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
2016-02-16 17:48:26 +03:00
func ( s * DB ) Joins ( query string , args ... interface { } ) * DB {
return s . clone ( ) . search . Joins ( query , args ... ) . db
2013-11-17 09:22:09 +04:00
}
2016-03-07 13:43:15 +03:00
// Scopes pass current database connection to arguments `func(*DB) *DB`, which could be used to add conditions dynamically
2016-03-07 16:09:05 +03:00
// func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
// return db.Where("amount > ?", 1000)
// }
//
// func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
// return func (db *gorm.DB) *gorm.DB {
// return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
// }
// }
//
// db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
2017-01-04 10:53:49 +03:00
// Refer https://jinzhu.github.io/gorm/crud.html#scopes
2013-11-18 10:35:44 +04:00
func ( s * DB ) Scopes ( funcs ... func ( * DB ) * DB ) * DB {
for _ , f := range funcs {
2015-02-17 17:55:14 +03:00
s = f ( s )
2013-11-18 10:35:44 +04:00
}
2015-02-17 17:55:14 +03:00
return s
2013-11-18 10:35:44 +04:00
}
2017-01-04 10:53:49 +03:00
// Unscoped return all record including deleted record, refer Soft Delete https://jinzhu.github.io/gorm/crud.html#soft-delete
2013-11-16 07:36:30 +04:00
func ( s * DB ) Unscoped ( ) * DB {
2015-03-12 10:01:59 +03:00
return s . clone ( ) . search . unscoped ( ) . db
2013-10-25 14:04:48 +04:00
}
2017-01-04 10:53:49 +03:00
// Attrs initialize struct with argument if record not found with `FirstOrInit` https://jinzhu.github.io/gorm/crud.html#firstorinit or `FirstOrCreate` https://jinzhu.github.io/gorm/crud.html#firstorcreate
2014-01-28 05:48:44 +04:00
func ( s * DB ) Attrs ( attrs ... interface { } ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Attrs ( attrs ... ) . db
2014-01-28 05:48:44 +04:00
}
2017-01-04 10:53:49 +03:00
// Assign assign result with argument regardless it is found or not with `FirstOrInit` https://jinzhu.github.io/gorm/crud.html#firstorinit or `FirstOrCreate` https://jinzhu.github.io/gorm/crud.html#firstorcreate
2014-01-28 05:48:44 +04:00
func ( s * DB ) Assign ( attrs ... interface { } ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Assign ( attrs ... ) . db
2014-01-28 05:48:44 +04:00
}
2016-03-07 13:43:15 +03:00
// First find first record that match given conditions, order by primary key
2013-11-16 07:36:30 +04:00
func ( s * DB ) First ( out interface { } , where ... interface { } ) * DB {
2018-02-10 14:31:55 +03:00
newScope := s . NewScope ( out )
2015-03-12 08:52:29 +03:00
newScope . Search . Limit ( 1 )
2019-03-10 14:33:49 +03:00
2015-03-23 06:07:39 +03:00
return newScope . Set ( "gorm:order_by_primary_key" , "ASC" ) .
2016-01-16 14:20:52 +03:00
inlineCondition ( where ... ) . callCallbacks ( s . parent . callbacks . queries ) . db
2013-10-25 14:04:48 +04:00
}
2018-02-13 04:18:42 +03:00
// Take return a record that match given conditions, the order will depend on the database implementation
func ( s * DB ) Take ( out interface { } , where ... interface { } ) * DB {
newScope := s . NewScope ( out )
newScope . Search . Limit ( 1 )
return newScope . inlineCondition ( where ... ) . callCallbacks ( s . parent . callbacks . queries ) . db
}
2016-03-07 13:43:15 +03:00
// Last find last record that match given conditions, order by primary key
2013-11-16 07:36:30 +04:00
func ( s * DB ) Last ( out interface { } , where ... interface { } ) * DB {
2018-02-10 14:31:55 +03:00
newScope := s . NewScope ( out )
2015-03-12 08:52:29 +03:00
newScope . Search . Limit ( 1 )
2015-03-23 06:07:39 +03:00
return newScope . Set ( "gorm:order_by_primary_key" , "DESC" ) .
2016-01-16 14:20:52 +03:00
inlineCondition ( where ... ) . callCallbacks ( s . parent . callbacks . queries ) . db
2013-10-31 13:31:00 +04:00
}
2014-01-28 05:30:30 +04:00
2016-03-07 13:43:15 +03:00
// Find find records that match given conditions
2013-11-16 07:36:30 +04:00
func ( s * DB ) Find ( out interface { } , where ... interface { } ) * DB {
2018-02-10 14:31:55 +03:00
return s . NewScope ( out ) . inlineCondition ( where ... ) . callCallbacks ( s . parent . callbacks . queries ) . db
2013-10-25 14:04:48 +04:00
}
2018-09-10 01:52:32 +03:00
//Preloads preloads relations, don`t touch out
func ( s * DB ) Preloads ( out interface { } ) * DB {
return s . NewScope ( out ) . InstanceSet ( "gorm:only_preload" , 1 ) . callCallbacks ( s . parent . callbacks . queries ) . db
}
2016-03-07 13:43:15 +03:00
// Scan scan value to a struct
2015-04-17 13:27:20 +03:00
func ( s * DB ) Scan ( dest interface { } ) * DB {
2018-02-10 14:31:55 +03:00
return s . NewScope ( s . Value ) . Set ( "gorm:query_destination" , dest ) . callCallbacks ( s . parent . callbacks . queries ) . db
2015-04-17 13:27:20 +03:00
}
2016-03-07 16:09:05 +03:00
// Row return `*sql.Row` with given conditions
2013-11-17 08:02:22 +04:00
func ( s * DB ) Row ( ) * sql . Row {
2014-01-28 05:48:44 +04:00
return s . NewScope ( s . Value ) . row ( )
2013-11-17 08:02:22 +04:00
}
2016-03-07 16:09:05 +03:00
// Rows return `*sql.Rows` with given conditions
2013-11-17 08:02:22 +04:00
func ( s * DB ) Rows ( ) ( * sql . Rows , error ) {
2014-01-28 05:48:44 +04:00
return s . NewScope ( s . Value ) . rows ( )
2013-11-17 08:02:22 +04:00
}
2016-03-07 13:43:15 +03:00
// ScanRows scan `*sql.Rows` to give struct
func ( s * DB ) ScanRows ( rows * sql . Rows , result interface { } ) error {
2016-02-14 18:29:06 +03:00
var (
2018-02-10 14:31:55 +03:00
scope = s . NewScope ( result )
clone = scope . db
2016-02-14 18:29:06 +03:00
columns , err = rows . Columns ( )
)
if clone . AddError ( err ) == nil {
2016-03-10 12:13:48 +03:00
scope . scan ( rows , columns , scope . Fields ( ) )
2016-02-14 18:29:06 +03:00
}
return clone . Error
}
2016-03-07 13:43:15 +03:00
// Pluck used to query single column from a model as a map
2016-03-07 16:09:05 +03:00
// var ages []int64
// db.Find(&users).Pluck("age", &ages)
2015-04-17 13:27:20 +03:00
func ( s * DB ) Pluck ( column string , value interface { } ) * DB {
return s . NewScope ( s . Value ) . pluck ( column , value ) . db
}
2016-03-07 13:43:15 +03:00
// Count get how many records for a model
2015-04-17 13:27:20 +03:00
func ( s * DB ) Count ( value interface { } ) * DB {
return s . NewScope ( s . Value ) . count ( value ) . db
}
2016-03-07 13:43:15 +03:00
// Related get related associations
2015-04-17 13:27:20 +03:00
func ( s * DB ) Related ( value interface { } , foreignKeys ... string ) * DB {
2018-02-10 14:31:55 +03:00
return s . NewScope ( s . Value ) . related ( value , foreignKeys ... ) . db
2013-10-30 11:21:58 +04:00
}
2016-03-08 16:45:20 +03:00
// FirstOrInit find first matched record or initialize a new one with given conditions (only works with struct, map conditions)
2017-01-04 10:53:49 +03:00
// https://jinzhu.github.io/gorm/crud.html#firstorinit
2013-11-16 07:36:30 +04:00
func ( s * DB ) FirstOrInit ( out interface { } , where ... interface { } ) * DB {
2013-11-16 14:01:44 +04:00
c := s . clone ( )
2015-02-17 17:55:14 +03:00
if result := c . First ( out , where ... ) ; result . Error != nil {
if ! result . RecordNotFound ( ) {
return result
2014-06-23 16:10:50 +04:00
}
2014-01-28 08:28:44 +04:00
c . NewScope ( out ) . inlineCondition ( where ... ) . initialize ( )
2014-01-28 06:23:31 +04:00
} else {
2016-03-09 11:18:01 +03:00
c . NewScope ( out ) . updatedAttrsWithValues ( c . search . assignAttrs )
2013-11-16 07:36:30 +04:00
}
2013-11-16 14:01:44 +04:00
return c
2013-10-31 04:15:19 +04:00
}
2016-03-07 13:43:15 +03:00
// FirstOrCreate find first matched record or create a new one with given conditions (only works with struct, map conditions)
2017-01-04 10:53:49 +03:00
// https://jinzhu.github.io/gorm/crud.html#firstorcreate
2013-11-16 07:36:30 +04:00
func ( s * DB ) FirstOrCreate ( out interface { } , where ... interface { } ) * DB {
2013-11-16 14:01:44 +04:00
c := s . clone ( )
2016-10-21 06:30:17 +03:00
if result := s . First ( out , where ... ) ; result . Error != nil {
2015-02-17 17:55:14 +03:00
if ! result . RecordNotFound ( ) {
return result
2014-06-23 16:10:50 +04:00
}
2016-10-21 06:30:17 +03:00
return c . NewScope ( out ) . inlineCondition ( where ... ) . initialize ( ) . callCallbacks ( c . parent . callbacks . creates ) . db
2015-03-12 08:52:29 +03:00
} else if len ( c . search . assignAttrs ) > 0 {
2016-10-21 06:30:17 +03:00
return c . NewScope ( out ) . InstanceSet ( "gorm:update_interface" , c . search . assignAttrs ) . callCallbacks ( c . parent . callbacks . updates ) . db
2013-11-16 07:36:30 +04:00
}
2013-11-16 14:01:44 +04:00
return c
2013-10-29 14:02:28 +04:00
}
2017-01-04 10:53:49 +03:00
// Update update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
2013-11-16 08:19:35 +04:00
func ( s * DB ) Update ( attrs ... interface { } ) * DB {
return s . Updates ( toSearchableMap ( attrs ... ) , true )
}
2017-01-04 10:53:49 +03:00
// Updates update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
2014-01-27 07:06:13 +04:00
func ( s * DB ) Updates ( values interface { } , ignoreProtectedAttrs ... bool ) * DB {
2018-02-10 14:31:55 +03:00
return s . NewScope ( s . Value ) .
2014-01-27 18:36:08 +04:00
Set ( "gorm:ignore_protected_attrs" , len ( ignoreProtectedAttrs ) > 0 ) .
2014-08-20 13:05:02 +04:00
InstanceSet ( "gorm:update_interface" , values ) .
2016-01-16 14:20:52 +03:00
callCallbacks ( s . parent . callbacks . updates ) . db
2013-11-16 08:19:35 +04:00
}
2017-01-04 10:53:49 +03:00
// UpdateColumn update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
2013-11-17 17:39:50 +04:00
func ( s * DB ) UpdateColumn ( attrs ... interface { } ) * DB {
2014-01-28 04:27:12 +04:00
return s . UpdateColumns ( toSearchableMap ( attrs ... ) )
2013-11-17 17:39:50 +04:00
}
2017-01-04 10:53:49 +03:00
// UpdateColumns update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
2014-01-28 04:27:12 +04:00
func ( s * DB ) UpdateColumns ( values interface { } ) * DB {
2018-02-10 14:31:55 +03:00
return s . NewScope ( s . Value ) .
2014-01-28 04:27:12 +04:00
Set ( "gorm:update_column" , true ) .
2015-03-29 00:15:12 +03:00
Set ( "gorm:save_associations" , false ) .
2014-08-20 13:05:02 +04:00
InstanceSet ( "gorm:update_interface" , values ) .
2016-01-16 14:20:52 +03:00
callCallbacks ( s . parent . callbacks . updates ) . db
2013-11-17 17:39:50 +04:00
}
2016-03-07 16:09:05 +03:00
// Save update value in database, if the value doesn't have primary key, will insert it
2013-11-16 07:36:30 +04:00
func ( s * DB ) Save ( value interface { } ) * DB {
2018-02-10 14:31:55 +03:00
scope := s . NewScope ( value )
2016-09-07 16:54:19 +03:00
if ! scope . PrimaryKeyZero ( ) {
newDB := scope . callCallbacks ( s . parent . callbacks . updates ) . db
if newDB . Error == nil && newDB . RowsAffected == 0 {
return s . New ( ) . FirstOrCreate ( value )
}
return newDB
2014-01-26 15:34:06 +04:00
}
2016-09-07 16:54:19 +03:00
return scope . callCallbacks ( s . parent . callbacks . creates ) . db
2013-10-29 14:02:28 +04:00
}
2016-03-07 13:43:15 +03:00
// Create insert the value into database
2014-06-12 00:51:27 +04:00
func ( s * DB ) Create ( value interface { } ) * DB {
2018-02-10 14:31:55 +03:00
scope := s . NewScope ( value )
2016-01-16 14:20:52 +03:00
return scope . callCallbacks ( s . parent . callbacks . creates ) . db
2014-06-12 00:51:27 +04:00
}
2016-03-07 16:09:05 +03:00
// Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition
2014-07-24 14:30:12 +04:00
func ( s * DB ) Delete ( value interface { } , where ... interface { } ) * DB {
2018-02-10 14:31:55 +03:00
return s . NewScope ( value ) . inlineCondition ( where ... ) . callCallbacks ( s . parent . callbacks . deletes ) . db
2013-10-25 14:04:48 +04:00
}
2016-03-07 13:43:15 +03:00
// Raw use raw sql as conditions, won't run it unless invoked by other methods
// db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)
2014-01-03 14:14:51 +04:00
func ( s * DB ) Raw ( sql string , values ... interface { } ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Raw ( true ) . Where ( sql , values ... ) . db
2014-01-03 14:14:51 +04:00
}
2016-03-07 13:43:15 +03:00
// Exec execute raw sql
2013-11-17 12:47:39 +04:00
func ( s * DB ) Exec ( sql string , values ... interface { } ) * DB {
2018-02-10 14:31:55 +03:00
scope := s . NewScope ( nil )
2018-02-11 18:52:38 +03:00
generatedSQL := scope . buildCondition ( map [ string ] interface { } { "query" : sql , "args" : values } , true )
2016-01-15 16:03:35 +03:00
generatedSQL = strings . TrimSuffix ( strings . TrimPrefix ( generatedSQL , "(" ) , ")" )
scope . Raw ( generatedSQL )
2014-01-28 06:29:12 +04:00
return scope . Exec ( ) . db
2013-10-25 14:04:48 +04:00
}
2016-03-07 13:43:15 +03:00
// Model specify the model you would like to run db operations
// // update all users's name to `hello`
// db.Model(&User{}).Update("name", "hello")
// // if user's primary key is non-blank, will use it as condition, then will only update the user's name to `hello`
// db.Model(&user).Update("name", "hello")
2013-11-16 07:36:30 +04:00
func ( s * DB ) Model ( value interface { } ) * DB {
c := s . clone ( )
2014-01-04 11:08:00 +04:00
c . Value = value
2013-11-16 07:36:30 +04:00
return c
2013-10-25 14:04:48 +04:00
}
2016-03-07 13:43:15 +03:00
// Table specify the table you would like to run db operations
2013-11-16 07:36:30 +04:00
func ( s * DB ) Table ( name string ) * DB {
2015-02-26 11:08:15 +03:00
clone := s . clone ( )
2015-03-12 08:52:29 +03:00
clone . search . Table ( name )
2015-02-26 11:08:15 +03:00
clone . Value = nil
return clone
2013-10-25 14:04:48 +04:00
}
2016-03-07 13:43:15 +03:00
// Debug start debug mode
2013-11-16 07:36:30 +04:00
func ( s * DB ) Debug ( ) * DB {
2013-11-16 11:01:31 +04:00
return s . clone ( ) . LogMode ( true )
2013-11-16 07:36:30 +04:00
}
2016-03-07 13:43:15 +03:00
// Begin begin a transaction
2013-11-16 07:36:30 +04:00
func ( s * DB ) Begin ( ) * DB {
c := s . clone ( )
2017-03-31 14:26:51 +03:00
if db , ok := c . db . ( sqlDb ) ; ok && db != nil {
2013-11-16 07:36:30 +04:00
tx , err := db . Begin ( )
2017-03-14 23:32:38 +03:00
c . db = interface { } ( tx ) . ( SQLCommon )
2018-07-27 02:35:53 +03:00
c . dialect . SetDB ( c . db )
2015-08-13 11:42:13 +03:00
c . AddError ( err )
2013-11-16 07:36:30 +04:00
} else {
2016-03-07 09:54:20 +03:00
c . AddError ( ErrCantStartTransaction )
2013-11-16 07:36:30 +04:00
}
return c
2013-10-29 05:01:48 +04:00
}
2016-03-07 13:43:15 +03:00
// Commit commit a transaction
2013-11-16 07:36:30 +04:00
func ( s * DB ) Commit ( ) * DB {
2018-04-16 17:18:51 +03:00
var emptySQLTx * sql . Tx
if db , ok := s . db . ( sqlTx ) ; ok && db != nil && db != emptySQLTx {
2015-08-13 11:42:13 +03:00
s . AddError ( db . Commit ( ) )
2013-11-16 07:36:30 +04:00
} else {
2016-03-07 09:54:20 +03:00
s . AddError ( ErrInvalidTransaction )
2013-11-16 07:36:30 +04:00
}
return s
}
2016-03-07 13:43:15 +03:00
// Rollback rollback a transaction
2013-11-16 07:36:30 +04:00
func ( s * DB ) Rollback ( ) * DB {
2018-05-12 09:28:15 +03:00
var emptySQLTx * sql . Tx
if db , ok := s . db . ( sqlTx ) ; ok && db != nil && db != emptySQLTx {
2019-06-10 15:14:44 +03:00
if err := db . Rollback ( ) ; err != nil && err != sql . ErrTxDone {
s . AddError ( err )
}
2013-11-16 07:36:30 +04:00
} else {
2016-03-07 09:54:20 +03:00
s . AddError ( ErrInvalidTransaction )
2013-11-16 07:36:30 +04:00
}
return s
2013-10-25 14:04:48 +04:00
}
2013-10-26 11:47:30 +04:00
2019-06-10 15:19:39 +03:00
// RollbackUnlessCommitted rollback a transaction if it has not yet been
// committed.
func ( s * DB ) RollbackUnlessCommitted ( ) * DB {
var emptySQLTx * sql . Tx
if db , ok := s . db . ( sqlTx ) ; ok && db != nil && db != emptySQLTx {
err := db . Rollback ( )
// Ignore the error indicating that the transaction has already
// been committed.
if err != sql . ErrTxDone {
s . AddError ( err )
}
} else {
s . AddError ( ErrInvalidTransaction )
}
return s
}
2016-03-07 16:09:05 +03:00
// NewRecord check if value's primary key is blank
2013-11-23 17:38:31 +04:00
func ( s * DB ) NewRecord ( value interface { } ) bool {
2018-02-10 14:31:55 +03:00
return s . NewScope ( value ) . PrimaryKeyZero ( )
2013-11-23 17:38:31 +04:00
}
2016-03-07 16:09:05 +03:00
// RecordNotFound check if returning ErrRecordNotFound error
2013-11-24 07:29:37 +04:00
func ( s * DB ) RecordNotFound ( ) bool {
2016-03-07 16:09:05 +03:00
for _ , err := range s . GetErrors ( ) {
if err == ErrRecordNotFound {
return true
}
}
return false
2013-11-24 07:29:37 +04:00
}
2016-01-15 16:03:35 +03:00
// CreateTable create table for models
func ( s * DB ) CreateTable ( models ... interface { } ) * DB {
2016-03-17 13:12:21 +03:00
db := s . Unscoped ( )
2016-01-15 16:03:35 +03:00
for _ , model := range models {
db = db . NewScope ( model ) . createTable ( ) . db
2015-08-26 06:54:07 +03:00
}
return db
2013-10-27 04:06:01 +04:00
}
2016-01-15 16:03:35 +03:00
// DropTable drop table for models
2015-08-26 06:54:07 +03:00
func ( s * DB ) DropTable ( values ... interface { } ) * DB {
db := s . clone ( )
for _ , value := range values {
2016-01-03 12:20:24 +03:00
if tableName , ok := value . ( string ) ; ok {
db = db . Table ( tableName )
}
2015-08-26 06:54:07 +03:00
db = db . NewScope ( value ) . dropTable ( ) . db
}
return db
2013-10-28 16:27:25 +04:00
}
2016-03-07 16:33:48 +03:00
// DropTableIfExists drop table if it is exist
func ( s * DB ) DropTableIfExists ( values ... interface { } ) * DB {
db := s . clone ( )
for _ , value := range values {
if s . HasTable ( value ) {
db . AddError ( s . DropTable ( value ) . Error )
}
}
return db
}
2016-03-07 13:43:15 +03:00
// HasTable check has table or not
2014-08-29 09:28:54 +04:00
func ( s * DB ) HasTable ( value interface { } ) bool {
2016-02-14 09:17:14 +03:00
var (
2018-02-10 14:31:55 +03:00
scope = s . NewScope ( value )
2016-02-14 09:17:14 +03:00
tableName string
)
if name , ok := value . ( string ) ; ok {
tableName = name
} else {
tableName = scope . TableName ( )
}
2016-02-15 09:09:24 +03:00
has := scope . Dialect ( ) . HasTable ( tableName )
2015-08-13 11:42:13 +03:00
s . AddError ( scope . db . Error )
2015-08-09 00:08:25 +03:00
return has
2014-08-29 09:28:54 +04:00
}
2016-03-07 13:43:15 +03:00
// AutoMigrate run auto migration for given models, will only add missing fields, won't delete/change current data
2014-08-20 07:56:39 +04:00
func ( s * DB ) AutoMigrate ( values ... interface { } ) * DB {
2016-03-17 13:12:21 +03:00
db := s . Unscoped ( )
2014-08-20 07:56:39 +04:00
for _ , value := range values {
2016-01-17 12:12:19 +03:00
db = db . NewScope ( value ) . autoMigrate ( ) . db
2014-08-20 07:56:39 +04:00
}
return db
2013-10-26 11:47:30 +04:00
}
2013-11-01 11:01:39 +04:00
2016-03-07 13:43:15 +03:00
// ModifyColumn modify column to type
2013-11-17 16:38:43 +04:00
func ( s * DB ) ModifyColumn ( column string , typ string ) * DB {
2018-02-10 14:31:55 +03:00
scope := s . NewScope ( s . Value )
2015-06-24 01:27:21 +03:00
scope . modifyColumn ( column , typ )
return scope . db
2013-11-01 11:01:39 +04:00
}
2013-11-07 05:09:54 +04:00
2016-03-07 13:43:15 +03:00
// DropColumn drop a column
2013-11-16 07:36:30 +04:00
func ( s * DB ) DropColumn ( column string ) * DB {
2018-02-10 14:31:55 +03:00
scope := s . NewScope ( s . Value )
2015-06-24 01:27:21 +03:00
scope . dropColumn ( column )
return scope . db
2013-11-07 05:09:54 +04:00
}
2013-11-11 09:16:08 +04:00
2016-03-07 13:43:15 +03:00
// AddIndex add index for columns with given name
func ( s * DB ) AddIndex ( indexName string , columns ... string ) * DB {
2016-01-12 08:44:16 +03:00
scope := s . Unscoped ( ) . NewScope ( s . Value )
2016-03-07 13:43:15 +03:00
scope . addIndex ( false , indexName , columns ... )
2015-06-24 01:27:21 +03:00
return scope . db
2014-06-01 02:35:56 +04:00
}
2016-03-07 13:43:15 +03:00
// AddUniqueIndex add unique index for columns with given name
func ( s * DB ) AddUniqueIndex ( indexName string , columns ... string ) * DB {
2016-03-17 13:12:21 +03:00
scope := s . Unscoped ( ) . NewScope ( s . Value )
2016-03-07 13:43:15 +03:00
scope . addIndex ( true , indexName , columns ... )
2015-06-24 01:27:21 +03:00
return scope . db
2015-03-02 18:02:40 +03:00
}
2016-03-07 13:43:15 +03:00
// RemoveIndex remove index with name
2015-03-02 18:02:40 +03:00
func ( s * DB ) RemoveIndex ( indexName string ) * DB {
2018-02-10 14:31:55 +03:00
scope := s . NewScope ( s . Value )
2015-06-24 01:27:21 +03:00
scope . removeIndex ( indexName )
return scope . db
2015-03-02 18:02:40 +03:00
}
2016-03-07 16:09:05 +03:00
// AddForeignKey Add foreign key to the given scope, e.g:
// db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT")
2015-02-07 14:04:10 +03:00
func ( s * DB ) AddForeignKey ( field string , dest string , onDelete string , onUpdate string ) * DB {
2018-02-10 14:31:55 +03:00
scope := s . NewScope ( s . Value )
2015-06-24 01:27:21 +03:00
scope . addForeignKey ( field , dest , onDelete , onUpdate )
2015-06-24 09:09:59 +03:00
return scope . db
2015-02-07 14:04:10 +03:00
}
2018-02-09 17:20:26 +03:00
// RemoveForeignKey Remove foreign key from the given scope, e.g:
// db.Model(&User{}).RemoveForeignKey("city_id", "cities(id)")
func ( s * DB ) RemoveForeignKey ( field string , dest string ) * DB {
scope := s . clone ( ) . NewScope ( s . Value )
scope . removeForeignKey ( field , dest )
return scope . db
}
2016-03-07 13:43:15 +03:00
// Association start `Association Mode` to handler relations things easir in that mode, refer: https://jinzhu.github.io/gorm/associations.html#association-mode
2014-07-30 10:30:21 +04:00
func ( s * DB ) Association ( column string ) * Association {
2015-02-17 17:55:14 +03:00
var err error
2016-12-05 13:30:07 +03:00
var scope = s . Set ( "gorm:association:source" , s . Value ) . NewScope ( s . Value )
2014-07-30 16:48:36 +04:00
2015-03-11 06:28:30 +03:00
if primaryField := scope . PrimaryField ( ) ; primaryField . IsBlank {
2015-02-17 17:55:14 +03:00
err = errors . New ( "primary key can't be nil" )
2014-07-30 16:48:36 +04:00
} else {
2015-02-17 17:55:14 +03:00
if field , ok := scope . FieldByName ( column ) ; ok {
2015-07-30 09:26:48 +03:00
if field . Relationship == nil || len ( field . Relationship . ForeignFieldNames ) == 0 {
2015-02-17 17:55:14 +03:00
err = fmt . Errorf ( "invalid association %v for %v" , column , scope . IndirectValue ( ) . Type ( ) )
} else {
2016-01-16 07:18:04 +03:00
return & Association { scope : scope , column : column , field : field }
2015-02-17 17:55:14 +03:00
}
} else {
err = fmt . Errorf ( "%v doesn't have column %v" , scope . IndirectValue ( ) . Type ( ) , column )
}
2014-07-30 16:48:36 +04:00
}
2015-02-17 17:55:14 +03:00
return & Association { Error : err }
2013-11-11 09:16:08 +04:00
}
2014-08-20 12:25:01 +04:00
2016-03-07 16:09:05 +03:00
// Preload preload associations with given conditions
// db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
2015-02-01 18:19:29 +03:00
func ( s * DB ) Preload ( column string , conditions ... interface { } ) * DB {
2015-03-12 08:52:29 +03:00
return s . clone ( ) . search . Preload ( column , conditions ... ) . db
2015-02-01 18:19:29 +03:00
}
2016-03-07 13:43:15 +03:00
// Set set setting by name, which could be used in callbacks, will clone a new db, and update its setting
2014-08-20 12:25:01 +04:00
func ( s * DB ) Set ( name string , value interface { } ) * DB {
2014-08-25 13:10:46 +04:00
return s . clone ( ) . InstantSet ( name , value )
2014-08-20 13:05:02 +04:00
}
2016-03-07 13:43:15 +03:00
// InstantSet instant set setting, will affect current db
2014-08-25 13:10:46 +04:00
func ( s * DB ) InstantSet ( name string , value interface { } ) * DB {
2018-09-10 01:26:29 +03:00
s . values . Store ( name , value )
2014-08-20 12:25:01 +04:00
return s
}
2016-03-07 13:43:15 +03:00
// Get get setting by name
2014-08-20 12:25:01 +04:00
func ( s * DB ) Get ( name string ) ( value interface { } , ok bool ) {
2018-09-10 01:26:29 +03:00
value , ok = s . values . Load ( name )
2014-08-20 12:25:01 +04:00
return
}
2015-03-19 13:23:54 +03:00
2016-03-07 13:43:15 +03:00
// SetJoinTableHandler set a model's join table handler for a relation
2015-03-19 13:23:54 +03:00
func ( s * DB ) SetJoinTableHandler ( source interface { } , column string , handler JoinTableHandlerInterface ) {
2015-06-23 09:19:59 +03:00
scope := s . NewScope ( source )
for _ , field := range scope . GetModelStruct ( ) . StructFields {
2015-03-19 13:23:54 +03:00
if field . Name == column || field . DBName == column {
2018-09-10 02:11:00 +03:00
if many2many , _ := field . TagSettingsGet ( "MANY2MANY" ) ; many2many != "" {
2015-03-20 06:11:30 +03:00
source := ( & Scope { Value : source } ) . GetModelStruct ( ) . ModelType
destination := ( & Scope { Value : reflect . New ( field . Struct . Type ) . Interface ( ) } ) . GetModelStruct ( ) . ModelType
handler . Setup ( field . Relationship , many2many , source , destination )
field . Relationship . JoinTableHandler = handler
2016-02-15 09:09:24 +03:00
if table := handler . Table ( s ) ; scope . Dialect ( ) . HasTable ( table ) {
2015-06-23 09:19:59 +03:00
s . Table ( table ) . AutoMigrate ( handler )
}
2015-03-20 06:11:30 +03:00
}
2015-03-19 13:23:54 +03:00
}
}
}
2015-08-13 11:42:13 +03:00
2016-03-07 13:43:15 +03:00
// AddError add error to the db
2015-08-13 11:42:13 +03:00
func ( s * DB ) AddError ( err error ) error {
if err != nil {
2016-03-07 09:54:20 +03:00
if err != ErrRecordNotFound {
2018-12-13 16:04:51 +03:00
if s . logMode == defaultLogMode {
2019-03-10 15:03:55 +03:00
go s . print ( "error" , fileWithLineNum ( ) , err )
2015-08-13 11:42:13 +03:00
} else {
s . log ( err )
}
Make gorm.Errors available for use outside gorm
gorm.Errors, which usefully implements `error` for an `[]error` as
returned by `DB.GetError()` was already exported, but because it used a
private field `errors`, it was not able to be created due to the
compile-time error:
implicit assignment of unexported field 'errors' in gorm.Errors literal
The trivial solution would be to export the `errors` field on
`gorm.Errors`, but this led to the issue that the common pattern of
checking `err != nil` failed because a struct{error: nil} != nil.
We can take advantage of type aliasing here to make Errors an []error,
which can in fact be nil and would pass `err != nil` on the happy path.
* Remove `(Errors) GetErrors()`, as it's less useful when Errors is an
[]error which can be iterated over. While this is technically a
breaking change, we never expose an Errors and its difficult to build
one (it can be done with the existing `(Errors) Add(error)`), but
awkwardly. This removal can be reverted without issue and we can make
it an identity method, but it seemed an opportune time to reduce API
surface area on something that likely isn't used.
* Remove errorsInterface, as it's not useful without `(Errors)
GetErrors()`
* Change `(*Errors) Add(error)` => `(Errors) Add(error...) Errors`
because we can't modify even a *Errors when it's a type alias. This is
more idiomatic as it follows the pattern of `slice = append(slice,
element)` Go developers are familiar with.
2016-10-25 19:22:50 +03:00
errors := Errors ( s . GetErrors ( ) )
2016-11-09 05:22:42 +03:00
errors = errors . Add ( err )
Make gorm.Errors available for use outside gorm
gorm.Errors, which usefully implements `error` for an `[]error` as
returned by `DB.GetError()` was already exported, but because it used a
private field `errors`, it was not able to be created due to the
compile-time error:
implicit assignment of unexported field 'errors' in gorm.Errors literal
The trivial solution would be to export the `errors` field on
`gorm.Errors`, but this led to the issue that the common pattern of
checking `err != nil` failed because a struct{error: nil} != nil.
We can take advantage of type aliasing here to make Errors an []error,
which can in fact be nil and would pass `err != nil` on the happy path.
* Remove `(Errors) GetErrors()`, as it's less useful when Errors is an
[]error which can be iterated over. While this is technically a
breaking change, we never expose an Errors and its difficult to build
one (it can be done with the existing `(Errors) Add(error)`), but
awkwardly. This removal can be reverted without issue and we can make
it an identity method, but it seemed an opportune time to reduce API
surface area on something that likely isn't used.
* Remove errorsInterface, as it's not useful without `(Errors)
GetErrors()`
* Change `(*Errors) Add(error)` => `(Errors) Add(error...) Errors`
because we can't modify even a *Errors when it's a type alias. This is
more idiomatic as it follows the pattern of `slice = append(slice,
element)` Go developers are familiar with.
2016-10-25 19:22:50 +03:00
if len ( errors ) > 1 {
2015-08-18 06:06:10 +03:00
err = errors
2015-08-14 09:53:26 +03:00
}
2015-08-13 11:42:13 +03:00
}
s . Error = err
}
return err
}
2016-03-07 16:09:05 +03:00
// GetErrors get happened errors from the db
2016-11-09 05:22:42 +03:00
func ( s * DB ) GetErrors ( ) [ ] error {
Make gorm.Errors available for use outside gorm
gorm.Errors, which usefully implements `error` for an `[]error` as
returned by `DB.GetError()` was already exported, but because it used a
private field `errors`, it was not able to be created due to the
compile-time error:
implicit assignment of unexported field 'errors' in gorm.Errors literal
The trivial solution would be to export the `errors` field on
`gorm.Errors`, but this led to the issue that the common pattern of
checking `err != nil` failed because a struct{error: nil} != nil.
We can take advantage of type aliasing here to make Errors an []error,
which can in fact be nil and would pass `err != nil` on the happy path.
* Remove `(Errors) GetErrors()`, as it's less useful when Errors is an
[]error which can be iterated over. While this is technically a
breaking change, we never expose an Errors and its difficult to build
one (it can be done with the existing `(Errors) Add(error)`), but
awkwardly. This removal can be reverted without issue and we can make
it an identity method, but it seemed an opportune time to reduce API
surface area on something that likely isn't used.
* Remove errorsInterface, as it's not useful without `(Errors)
GetErrors()`
* Change `(*Errors) Add(error)` => `(Errors) Add(error...) Errors`
because we can't modify even a *Errors when it's a type alias. This is
more idiomatic as it follows the pattern of `slice = append(slice,
element)` Go developers are familiar with.
2016-10-25 19:22:50 +03:00
if errs , ok := s . Error . ( Errors ) ; ok {
return errs
2015-08-14 09:53:26 +03:00
} else if s . Error != nil {
2015-08-13 11:42:13 +03:00
return [ ] error { s . Error }
}
2016-11-09 05:22:42 +03:00
return [ ] error { }
2015-08-13 11:42:13 +03:00
}
2016-03-08 16:45:20 +03:00
////////////////////////////////////////////////////////////////////////////////
2017-02-05 08:31:31 +03:00
// Private Methods For DB
2016-03-08 16:45:20 +03:00
////////////////////////////////////////////////////////////////////////////////
func ( s * DB ) clone ( ) * DB {
2017-07-23 11:04:22 +03:00
db := & DB {
2016-11-04 19:41:31 +03:00
db : s . db ,
parent : s . parent ,
logger : s . logger ,
logMode : s . logMode ,
Value : s . Value ,
Error : s . Error ,
blockGlobalUpdate : s . blockGlobalUpdate ,
2018-07-27 02:35:53 +03:00
dialect : newDialect ( s . dialect . GetName ( ) , s . db ) ,
2016-11-04 19:41:31 +03:00
}
2016-03-08 16:45:20 +03:00
2018-09-10 01:26:29 +03:00
s . values . Range ( func ( k , v interface { } ) bool {
db . values . Store ( k , v )
return true
} )
2016-03-08 16:45:20 +03:00
if s . search == nil {
db . search = & search { limit : - 1 , offset : - 1 }
} else {
db . search = s . search . clone ( )
}
2017-07-23 11:04:22 +03:00
db . search . db = db
return db
2016-03-08 16:45:20 +03:00
}
func ( s * DB ) print ( v ... interface { } ) {
2017-02-05 08:31:31 +03:00
s . logger . Print ( v ... )
2016-03-08 16:45:20 +03:00
}
func ( s * DB ) log ( v ... interface { } ) {
2018-12-13 16:04:51 +03:00
if s != nil && s . logMode == detailedLogMode {
2016-03-08 16:45:20 +03:00
s . print ( append ( [ ] interface { } { "log" , fileWithLineNum ( ) } , v ... ) ... )
}
}
func ( s * DB ) slog ( sql string , t time . Time , vars ... interface { } ) {
2018-12-13 16:04:51 +03:00
if s . logMode == detailedLogMode {
2017-07-23 11:04:22 +03:00
s . print ( "sql" , fileWithLineNum ( ) , NowFunc ( ) . Sub ( t ) , sql , vars , s . RowsAffected )
2016-03-08 16:45:20 +03:00
}
}