2014-01-26 08:41:37 +04:00
package gorm
2014-01-26 09:51:23 +04:00
import (
2017-10-23 05:50:44 +03:00
"bytes"
2016-01-13 11:53:04 +03:00
"database/sql"
2016-03-08 16:45:20 +03:00
"database/sql/driver"
2014-01-26 09:51:23 +04:00
"errors"
"fmt"
2017-10-23 05:50:44 +03:00
"reflect"
2015-08-01 04:25:06 +03:00
"regexp"
2014-01-26 10:18:21 +04:00
"strings"
2016-03-08 16:45:20 +03:00
"time"
2014-01-26 09:51:23 +04:00
)
2014-01-26 08:41:37 +04:00
2016-03-07 16:09:05 +03:00
// Scope contain current operation's information when you perform any operation on the database
2014-01-26 08:41:37 +04:00
type Scope struct {
2014-11-11 06:46:21 +03:00
Search * search
2015-03-12 08:52:29 +03:00
Value interface { }
2016-03-07 09:54:20 +03:00
SQL string
SQLVars [ ] interface { }
2014-11-11 06:46:21 +03:00
db * DB
2016-01-15 16:03:35 +03:00
instanceID string
2015-03-12 08:52:29 +03:00
primaryKeyField * Field
skipLeft bool
2016-03-08 17:29:58 +03:00
fields * [ ] * Field
2015-03-13 06:01:05 +03:00
selectAttrs * [ ] string
2014-07-30 10:58:00 +04:00
}
2016-03-07 09:54:20 +03:00
// IndirectValue return scope's reflect value's indirect value
2014-07-30 10:58:00 +04:00
func ( scope * Scope ) IndirectValue ( ) reflect . Value {
2016-01-18 07:20:27 +03:00
return indirect ( reflect . ValueOf ( scope . Value ) )
2014-01-26 08:41:37 +04:00
}
2014-01-29 15:14:37 +04:00
// New create a new Scope without search information
2014-01-27 04:26:59 +04:00
func ( scope * Scope ) New ( value interface { } ) * Scope {
2015-02-26 07:35:33 +03:00
return & Scope { db : scope . NewDB ( ) , Search : & search { } , Value : value }
2014-01-27 04:26:59 +04:00
}
2016-03-08 17:29:58 +03:00
////////////////////////////////////////////////////////////////////////////////
// Scope DB
////////////////////////////////////////////////////////////////////////////////
// DB return scope's DB connection
func ( scope * Scope ) DB ( ) * DB {
return scope . db
}
2014-01-29 15:14:37 +04:00
// NewDB create a new DB without search information
2014-01-27 04:26:59 +04:00
func ( scope * Scope ) NewDB ( ) * DB {
2015-02-26 07:35:33 +03:00
if scope . db != nil {
db := scope . db . clone ( )
db . search = nil
2015-02-26 11:08:15 +03:00
db . Value = nil
2015-02-26 07:35:33 +03:00
return db
}
return nil
2014-01-27 04:26:59 +04:00
}
2016-03-07 09:54:20 +03:00
// SQLDB return *sql.DB
2017-03-14 23:32:38 +03:00
func ( scope * Scope ) SQLDB ( ) SQLCommon {
2014-01-26 08:41:37 +04:00
return scope . db . db
}
2016-03-08 17:29:58 +03:00
// Dialect get dialect
func ( scope * Scope ) Dialect ( ) Dialect {
2018-07-27 02:35:53 +03:00
return scope . db . dialect
2014-01-29 08:00:57 +04:00
}
2016-03-07 16:09:05 +03:00
// Quote used to quote string to escape them for database
2014-01-29 08:00:57 +04:00
func ( scope * Scope ) Quote ( str string ) string {
2018-11-03 16:56:27 +03:00
if strings . Contains ( str , "." ) {
2015-02-24 13:02:22 +03:00
newStrs := [ ] string { }
2015-02-26 07:35:33 +03:00
for _ , str := range strings . Split ( str , "." ) {
2015-02-24 13:02:22 +03:00
newStrs = append ( newStrs , scope . Dialect ( ) . Quote ( str ) )
}
return strings . Join ( newStrs , "." )
}
2016-01-15 16:03:35 +03:00
return scope . Dialect ( ) . Quote ( str )
2014-01-29 08:00:57 +04:00
}
2016-03-07 16:09:05 +03:00
// Err add error to Scope
2014-01-26 08:41:37 +04:00
func ( scope * Scope ) Err ( err error ) error {
if err != nil {
2015-08-13 11:42:13 +03:00
scope . db . AddError ( err )
2014-01-26 08:41:37 +04:00
}
return err
}
2016-03-08 17:29:58 +03:00
// HasError check if there are any error
func ( scope * Scope ) HasError ( ) bool {
return scope . db . Error != nil
}
2014-01-29 15:14:37 +04:00
// Log print log message
2014-01-28 04:27:12 +04:00
func ( scope * Scope ) Log ( v ... interface { } ) {
scope . db . log ( v ... )
}
2016-03-08 17:29:58 +03:00
// SkipLeft skip remaining callbacks
func ( scope * Scope ) SkipLeft ( ) {
scope . skipLeft = true
}
// Fields get value's fields
func ( scope * Scope ) Fields ( ) [ ] * Field {
if scope . fields == nil {
var (
fields [ ] * Field
indirectScopeValue = scope . IndirectValue ( )
isStruct = indirectScopeValue . Kind ( ) == reflect . Struct
)
for _ , structField := range scope . GetModelStruct ( ) . StructFields {
if isStruct {
fieldValue := indirectScopeValue
for _ , name := range structField . Names {
2018-02-13 05:00:07 +03:00
if fieldValue . Kind ( ) == reflect . Ptr && fieldValue . IsNil ( ) {
fieldValue . Set ( reflect . New ( fieldValue . Type ( ) . Elem ( ) ) )
}
2016-03-08 17:29:58 +03:00
fieldValue = reflect . Indirect ( fieldValue ) . FieldByName ( name )
}
fields = append ( fields , & Field { StructField : structField , Field : fieldValue , IsBlank : isBlank ( fieldValue ) } )
} else {
fields = append ( fields , & Field { StructField : structField , IsBlank : true } )
}
}
scope . fields = & fields
}
return * scope . fields
}
// FieldByName find `gorm.Field` with field name or db name
func ( scope * Scope ) FieldByName ( name string ) ( field * Field , ok bool ) {
var (
2018-09-10 00:52:20 +03:00
dbName = ToColumnName ( name )
2016-03-08 17:29:58 +03:00
mostMatchedField * Field
)
for _ , field := range scope . Fields ( ) {
if field . Name == name || field . DBName == name {
return field , true
}
if field . DBName == dbName {
mostMatchedField = field
}
}
return mostMatchedField , mostMatchedField != nil
2014-01-26 08:41:37 +04:00
}
2016-03-07 09:54:20 +03:00
// PrimaryFields return scope's primary fields
2016-03-07 07:15:15 +03:00
func ( scope * Scope ) PrimaryFields ( ) ( fields [ ] * Field ) {
for _ , field := range scope . Fields ( ) {
if field . IsPrimaryKey {
fields = append ( fields , field )
}
2015-06-29 13:04:15 +03:00
}
return fields
}
2016-03-07 09:54:20 +03:00
// PrimaryField return scope's main primary field, if defined more that one primary fields, will return the one having column name `id` or the first one
2015-03-11 06:28:30 +03:00
func ( scope * Scope ) PrimaryField ( ) * Field {
if primaryFields := scope . GetModelStruct ( ) . PrimaryFields ; len ( primaryFields ) > 0 {
if len ( primaryFields ) > 1 {
2016-03-07 07:15:15 +03:00
if field , ok := scope . FieldByName ( "id" ) ; ok {
2015-03-11 06:28:30 +03:00
return field
}
}
2016-03-07 07:15:15 +03:00
return scope . PrimaryFields ( ) [ 0 ]
2015-02-17 09:30:37 +03:00
}
return nil
2014-11-11 06:46:21 +03:00
}
2016-03-07 16:09:05 +03:00
// PrimaryKey get main primary field's db name
2014-11-11 06:46:21 +03:00
func ( scope * Scope ) PrimaryKey ( ) string {
2015-03-11 06:28:30 +03:00
if field := scope . PrimaryField ( ) ; field != nil {
2014-11-11 06:46:21 +03:00
return field . DBName
}
2015-02-17 02:15:34 +03:00
return ""
2014-01-26 08:41:37 +04:00
}
2016-03-07 16:09:05 +03:00
// PrimaryKeyZero check main primary field's value is blank or not
2014-01-26 13:10:33 +04:00
func ( scope * Scope ) PrimaryKeyZero ( ) bool {
2015-03-11 06:28:30 +03:00
field := scope . PrimaryField ( )
2015-02-17 17:55:14 +03:00
return field == nil || field . IsBlank
2014-01-26 13:10:33 +04:00
}
2014-01-29 15:14:37 +04:00
// PrimaryKeyValue get the primary key's value
2014-01-26 13:10:33 +04:00
func ( scope * Scope ) PrimaryKeyValue ( ) interface { } {
2015-03-11 06:28:30 +03:00
if field := scope . PrimaryField ( ) ; field != nil && field . Field . IsValid ( ) {
2014-11-11 06:46:21 +03:00
return field . Field . Interface ( )
2014-01-26 13:10:33 +04:00
}
2015-02-17 02:15:34 +03:00
return 0
2014-01-26 13:10:33 +04:00
}
2014-01-29 15:14:37 +04:00
// HasColumn to check if has column
2015-01-19 11:23:33 +03:00
func ( scope * Scope ) HasColumn ( column string ) bool {
2015-02-17 12:40:21 +03:00
for _ , field := range scope . GetStructFields ( ) {
2015-02-17 17:55:14 +03:00
if field . IsNormal && ( field . Name == column || field . DBName == column ) {
return true
2015-02-17 12:40:21 +03:00
}
2014-09-01 13:03:58 +04:00
}
2015-02-17 12:40:21 +03:00
return false
2014-01-28 08:28:44 +04:00
}
2016-03-07 16:09:05 +03:00
// SetColumn to set the column's value, column could be field or field's name/dbname
2014-09-30 16:02:51 +04:00
func ( scope * Scope ) SetColumn ( column interface { } , value interface { } ) error {
2016-02-18 17:24:35 +03:00
var updateAttrs = map [ string ] interface { } { }
if attrs , ok := scope . InstanceGet ( "gorm:update_attrs" ) ; ok {
updateAttrs = attrs . ( map [ string ] interface { } )
defer scope . InstanceSet ( "gorm:update_attrs" , updateAttrs )
}
2014-09-02 15:03:01 +04:00
if field , ok := column . ( * Field ) ; ok {
2016-02-18 17:24:35 +03:00
updateAttrs [ field . DBName ] = value
2014-09-02 15:03:01 +04:00
return field . Set ( value )
2015-04-16 09:08:13 +03:00
} else if name , ok := column . ( string ) ; ok {
2016-03-07 07:15:15 +03:00
var (
dbName = ToDBName ( name )
mostMatchedField * Field
)
for _ , field := range scope . Fields ( ) {
if field . DBName == value {
updateAttrs [ field . DBName ] = value
return field . Set ( value )
}
2019-10-17 18:38:37 +03:00
if ! field . IsIgnored && ( ( field . DBName == dbName ) || ( field . Name == name && mostMatchedField == nil ) ) {
2016-03-07 07:15:15 +03:00
mostMatchedField = field
}
2014-08-30 18:39:28 +04:00
}
2015-04-16 09:08:13 +03:00
2016-03-07 07:15:15 +03:00
if mostMatchedField != nil {
updateAttrs [ mostMatchedField . DBName ] = value
return mostMatchedField . Set ( value )
2015-04-16 09:08:13 +03:00
}
2014-08-30 18:39:28 +04:00
}
2014-09-30 16:02:51 +04:00
return errors . New ( "could not convert column to field" )
2014-01-26 08:41:37 +04:00
}
2016-03-07 16:09:05 +03:00
// CallMethod call scope value's method, if it is a slice, will call its element's method one by one
2016-01-17 16:35:32 +03:00
func ( scope * Scope ) CallMethod ( methodName string ) {
if scope . Value == nil {
return
}
if indirectScopeValue := scope . IndirectValue ( ) ; indirectScopeValue . Kind ( ) == reflect . Slice {
for i := 0 ; i < indirectScopeValue . Len ( ) ; i ++ {
scope . callMethod ( methodName , indirectScopeValue . Index ( i ) )
2014-01-28 05:25:30 +04:00
}
} else {
2016-01-17 16:35:32 +03:00
scope . callMethod ( methodName , indirectScopeValue )
2014-01-28 05:25:30 +04:00
}
2014-01-26 08:41:37 +04:00
}
2016-03-07 16:09:05 +03:00
// AddToVars add value as sql's vars, used to prevent SQL injection
2014-01-26 08:41:37 +04:00
func ( scope * Scope ) AddToVars ( value interface { } ) string {
2017-08-02 02:41:43 +03:00
_ , skipBindVar := scope . InstanceGet ( "skip_bindvar" )
2019-10-17 18:44:34 +03:00
if expr , ok := value . ( * SqlExpr ) ; ok {
2015-02-24 17:06:35 +03:00
exp := expr . expr
for _ , arg := range expr . args {
2017-08-02 02:41:43 +03:00
if skipBindVar {
scope . AddToVars ( arg )
} else {
exp = strings . Replace ( exp , "?" , scope . AddToVars ( arg ) , 1 )
}
2015-02-24 17:06:35 +03:00
}
return exp
}
2016-01-15 16:03:35 +03:00
2016-03-07 09:54:20 +03:00
scope . SQLVars = append ( scope . SQLVars , value )
2017-08-02 02:41:43 +03:00
if skipBindVar {
return "?"
}
2016-03-07 09:54:20 +03:00
return scope . Dialect ( ) . BindVar ( len ( scope . SQLVars ) )
2014-01-26 08:41:37 +04:00
}
2016-03-08 17:29:58 +03:00
// SelectAttrs return selected attributes
func ( scope * Scope ) SelectAttrs ( ) [ ] string {
if scope . selectAttrs == nil {
attrs := [ ] string { }
for _ , value := range scope . Search . selects {
if str , ok := value . ( string ) ; ok {
attrs = append ( attrs , str )
} else if strs , ok := value . ( [ ] string ) ; ok {
attrs = append ( attrs , strs ... )
} else if strs , ok := value . ( [ ] interface { } ) ; ok {
for _ , str := range strs {
attrs = append ( attrs , fmt . Sprintf ( "%v" , str ) )
}
}
}
scope . selectAttrs = & attrs
}
return * scope . selectAttrs
}
// OmitAttrs return omitted attributes
func ( scope * Scope ) OmitAttrs ( ) [ ] string {
return scope . Search . omits
}
2015-04-08 06:36:01 +03:00
type tabler interface {
TableName ( ) string
}
type dbTabler interface {
TableName ( * DB ) string
}
2016-01-13 09:58:30 +03:00
// TableName return table name
2014-01-26 08:41:37 +04:00
func ( scope * Scope ) TableName ( ) string {
2015-03-12 08:52:29 +03:00
if scope . Search != nil && len ( scope . Search . tableName ) > 0 {
return scope . Search . tableName
2015-02-17 03:34:01 +03:00
}
2015-04-08 06:36:01 +03:00
if tabler , ok := scope . Value . ( tabler ) ; ok {
return tabler . TableName ( )
}
if tabler , ok := scope . Value . ( dbTabler ) ; ok {
return tabler . TableName ( scope . db )
}
2015-06-30 05:39:29 +03:00
return scope . GetModelStruct ( ) . TableName ( scope . db . Model ( scope . Value ) )
2014-01-26 10:18:21 +04:00
}
2016-01-13 09:58:30 +03:00
// QuotedTableName return quoted table name
2015-02-26 11:08:15 +03:00
func ( scope * Scope ) QuotedTableName ( ) ( name string ) {
2015-03-12 08:52:29 +03:00
if scope . Search != nil && len ( scope . Search . tableName ) > 0 {
2018-11-03 16:56:27 +03:00
if strings . Contains ( scope . Search . tableName , " " ) {
2015-05-19 05:43:32 +03:00
return scope . Search . tableName
}
2015-03-12 08:52:29 +03:00
return scope . Quote ( scope . Search . tableName )
2014-06-03 13:15:05 +04:00
}
2016-01-15 16:03:35 +03:00
return scope . Quote ( scope . TableName ( ) )
2014-06-03 13:15:05 +04:00
}
2016-03-07 09:54:20 +03:00
// CombinedConditionSql return combined condition sql
2014-01-29 04:55:45 +04:00
func ( scope * Scope ) CombinedConditionSql ( ) string {
2017-08-02 02:41:43 +03:00
joinSQL := scope . joinsSQL ( )
whereSQL := scope . whereSQL ( )
2016-10-26 17:30:20 +03:00
if scope . Search . raw {
2017-08-02 02:41:43 +03:00
whereSQL = strings . TrimSuffix ( strings . TrimPrefix ( whereSQL , "WHERE (" ) , ")" )
2016-10-26 17:30:20 +03:00
}
2017-08-02 02:41:43 +03:00
return joinSQL + whereSQL + scope . groupSQL ( ) +
2016-03-07 09:54:20 +03:00
scope . havingSQL ( ) + scope . orderSQL ( ) + scope . limitAndOffsetSQL ( )
2014-01-26 10:55:41 +04:00
}
2016-03-07 16:09:05 +03:00
// Raw set raw sql
2014-01-28 11:54:19 +04:00
func ( scope * Scope ) Raw ( sql string ) * Scope {
2017-04-18 11:13:02 +03:00
scope . SQL = strings . Replace ( sql , "$$$" , "?" , - 1 )
2014-01-28 11:54:19 +04:00
return scope
2014-01-26 08:41:37 +04:00
}
2016-03-07 16:09:05 +03:00
// Exec perform generated SQL
2014-01-28 06:23:31 +04:00
func ( scope * Scope ) Exec ( ) * Scope {
2019-06-10 15:45:42 +03:00
defer scope . trace ( scope . db . nowFunc ( ) )
2014-01-28 11:54:19 +04:00
2014-01-26 10:18:21 +04:00
if ! scope . HasError ( ) {
2016-03-07 09:54:20 +03:00
if result , err := scope . SQLDB ( ) . Exec ( scope . SQL , scope . SQLVars ... ) ; scope . Err ( err ) == nil {
2015-07-02 22:06:06 +03:00
if count , err := result . RowsAffected ( ) ; scope . Err ( err ) == nil {
2014-06-05 13:58:14 +04:00
scope . db . RowsAffected = count
}
}
2014-01-26 10:18:21 +04:00
}
2014-01-28 06:23:31 +04:00
return scope
2014-01-26 08:41:37 +04:00
}
2014-01-26 13:10:33 +04:00
2014-01-29 15:14:37 +04:00
// Set set value by name
2014-08-20 13:05:02 +04:00
func ( scope * Scope ) Set ( name string , value interface { } ) * Scope {
2014-08-25 13:10:46 +04:00
scope . db . InstantSet ( name , value )
2014-08-20 13:05:02 +04:00
return scope
2014-01-27 07:56:04 +04:00
}
2016-03-07 16:09:05 +03:00
// Get get setting by name
2014-08-20 12:25:01 +04:00
func ( scope * Scope ) Get ( name string ) ( interface { } , bool ) {
return scope . db . Get ( name )
2014-01-29 15:14:37 +04:00
}
2016-01-15 16:03:35 +03:00
// InstanceID get InstanceID for scope
func ( scope * Scope ) InstanceID ( ) string {
if scope . instanceID == "" {
scope . instanceID = fmt . Sprintf ( "%v%v" , & scope , & scope . db )
2014-08-20 13:05:02 +04:00
}
2016-01-15 16:03:35 +03:00
return scope . instanceID
2014-08-20 13:05:02 +04:00
}
2016-03-07 16:09:05 +03:00
// InstanceSet set instance setting for current operation, but not for operations in callbacks, like saving associations callback
2014-08-20 13:05:02 +04:00
func ( scope * Scope ) InstanceSet ( name string , value interface { } ) * Scope {
2016-01-15 16:03:35 +03:00
return scope . Set ( name + scope . InstanceID ( ) , value )
2014-08-20 13:05:02 +04:00
}
2016-03-07 16:09:05 +03:00
// InstanceGet get instance setting from current operation
2014-08-20 13:05:02 +04:00
func ( scope * Scope ) InstanceGet ( name string ) ( interface { } , bool ) {
2016-01-15 16:03:35 +03:00
return scope . Get ( name + scope . InstanceID ( ) )
2014-08-20 13:05:02 +04:00
}
2014-01-29 15:14:37 +04:00
// Begin start a transaction
2014-01-26 13:10:33 +04:00
func ( scope * Scope ) Begin ( ) * Scope {
2016-03-07 09:54:20 +03:00
if db , ok := scope . SQLDB ( ) . ( sqlDb ) ; ok {
2019-06-10 15:12:13 +03:00
if tx , err := db . Begin ( ) ; scope . Err ( err ) == nil {
2017-03-14 23:32:38 +03:00
scope . db . db = interface { } ( tx ) . ( SQLCommon )
2014-08-20 13:05:02 +04:00
scope . InstanceSet ( "gorm:started_transaction" , true )
2014-01-27 06:47:37 +04:00
}
2014-01-26 13:10:33 +04:00
}
return scope
}
2016-03-07 16:09:05 +03:00
// CommitOrRollback commit current transaction if no error happened, otherwise will rollback it
2014-01-26 13:10:33 +04:00
func ( scope * Scope ) CommitOrRollback ( ) * Scope {
2014-08-20 13:05:02 +04:00
if _ , ok := scope . InstanceGet ( "gorm:started_transaction" ) ; ok {
2014-01-26 13:10:33 +04:00
if db , ok := scope . db . db . ( sqlTx ) ; ok {
if scope . HasError ( ) {
db . Rollback ( )
} else {
2016-01-04 08:32:35 +03:00
scope . Err ( db . Commit ( ) )
2014-01-26 13:10:33 +04:00
}
scope . db . db = scope . db . parent . db
}
}
return scope
}
2015-03-12 12:47:31 +03:00
2016-03-08 17:29:58 +03:00
////////////////////////////////////////////////////////////////////////////////
// Private Methods For *gorm.Scope
////////////////////////////////////////////////////////////////////////////////
func ( scope * Scope ) callMethod ( methodName string , reflectValue reflect . Value ) {
2016-04-04 17:49:18 +03:00
// Only get address from non-pointer
if reflectValue . CanAddr ( ) && reflectValue . Kind ( ) != reflect . Ptr {
2016-03-08 17:29:58 +03:00
reflectValue = reflectValue . Addr ( )
}
if methodValue := reflectValue . MethodByName ( methodName ) ; methodValue . IsValid ( ) {
switch method := methodValue . Interface ( ) . ( type ) {
case func ( ) :
method ( )
case func ( * Scope ) :
method ( scope )
case func ( * DB ) :
newDB := scope . NewDB ( )
method ( newDB )
scope . Err ( newDB . Error )
case func ( ) error :
scope . Err ( method ( ) )
case func ( * Scope ) error :
scope . Err ( method ( scope ) )
case func ( * DB ) error :
newDB := scope . NewDB ( )
scope . Err ( method ( newDB ) )
scope . Err ( newDB . Error )
default :
scope . Err ( fmt . Errorf ( "unsupported function %v" , methodName ) )
}
}
2015-03-12 12:47:31 +03:00
}
2016-01-13 11:53:04 +03:00
2016-12-20 06:36:13 +03:00
var (
2017-07-03 16:49:54 +03:00
columnRegexp = regexp . MustCompile ( "^[a-zA-Z\\d]+(\\.[a-zA-Z\\d]+)*$" ) // only match string like `name`, `users.name`
isNumberRegexp = regexp . MustCompile ( "^\\s*\\d+\\s*$" ) // match if string is number
2018-02-11 10:52:52 +03:00
comparisonRegexp = regexp . MustCompile ( "(?i) (=|<>|(>|<)(=?)|LIKE|IS|IN) " )
2016-12-20 06:36:13 +03:00
countingQueryRegexp = regexp . MustCompile ( "(?i)^count(.+)$" )
)
2016-03-23 05:29:52 +03:00
2016-03-08 17:29:58 +03:00
func ( scope * Scope ) quoteIfPossible ( str string ) string {
2016-03-23 05:29:52 +03:00
if columnRegexp . MatchString ( str ) {
2016-03-08 17:29:58 +03:00
return scope . Quote ( str )
}
return str
}
2016-03-08 16:45:20 +03:00
2016-03-10 12:13:48 +03:00
func ( scope * Scope ) scan ( rows * sql . Rows , columns [ ] string , fields [ ] * Field ) {
var (
ignored interface { }
values = make ( [ ] interface { } , len ( columns ) )
2016-09-13 04:29:36 +03:00
selectFields [ ] * Field
2016-03-10 12:13:48 +03:00
selectedColumnsMap = map [ string ] int { }
2016-09-13 04:29:36 +03:00
resetFields = map [ int ] * Field { }
2016-03-10 12:13:48 +03:00
)
2016-01-13 11:53:04 +03:00
for index , column := range columns {
2016-03-10 12:13:48 +03:00
values [ index ] = & ignored
selectFields = fields
2018-09-10 01:12:58 +03:00
offset := 0
2016-03-10 12:13:48 +03:00
if idx , ok := selectedColumnsMap [ column ] ; ok {
2018-09-10 01:12:58 +03:00
offset = idx + 1
selectFields = selectFields [ offset : ]
2016-03-10 12:13:48 +03:00
}
2016-03-10 12:35:19 +03:00
for fieldIndex , field := range selectFields {
2016-03-10 12:13:48 +03:00
if field . DBName == column {
if field . Field . Kind ( ) == reflect . Ptr {
values [ index ] = field . Field . Addr ( ) . Interface ( )
} else {
reflectValue := reflect . New ( reflect . PtrTo ( field . Struct . Type ) )
reflectValue . Elem ( ) . Set ( field . Field . Addr ( ) )
values [ index ] = reflectValue . Interface ( )
2016-09-13 04:29:36 +03:00
resetFields [ index ] = field
2016-03-10 12:13:48 +03:00
}
2016-03-10 12:35:19 +03:00
2018-09-10 01:12:58 +03:00
selectedColumnsMap [ column ] = offset + fieldIndex
2016-09-13 04:29:36 +03:00
if field . IsNormal {
break
}
2016-01-13 11:53:04 +03:00
}
}
}
scope . Err ( rows . Scan ( values ... ) )
2016-09-13 04:29:36 +03:00
for index , field := range resetFields {
2016-03-10 12:13:48 +03:00
if v := reflect . ValueOf ( values [ index ] ) . Elem ( ) . Elem ( ) ; v . IsValid ( ) {
field . Field . Set ( v )
2016-01-13 11:53:04 +03:00
}
}
}
2016-03-08 17:29:58 +03:00
2016-03-08 16:45:20 +03:00
func ( scope * Scope ) primaryCondition ( value interface { } ) string {
2016-08-13 16:23:18 +03:00
return fmt . Sprintf ( "(%v.%v = %v)" , scope . QuotedTableName ( ) , scope . Quote ( scope . PrimaryKey ( ) ) , value )
2016-03-08 16:45:20 +03:00
}
2018-02-11 18:52:38 +03:00
func ( scope * Scope ) buildCondition ( clause map [ string ] interface { } , include bool ) ( str string ) {
var (
quotedTableName = scope . QuotedTableName ( )
quotedPrimaryKey = scope . Quote ( scope . PrimaryKey ( ) )
equalSQL = "="
inSQL = "IN"
)
// If building not conditions
if ! include {
equalSQL = "<>"
inSQL = "NOT IN"
}
2016-03-08 16:45:20 +03:00
switch value := clause [ "query" ] . ( type ) {
2018-02-11 18:52:38 +03:00
case sql . NullInt64 :
return fmt . Sprintf ( "(%v.%v %s %v)" , quotedTableName , quotedPrimaryKey , equalSQL , value . Int64 )
case int , int8 , int16 , int32 , int64 , uint , uint8 , uint16 , uint32 , uint64 :
return fmt . Sprintf ( "(%v.%v %s %v)" , quotedTableName , quotedPrimaryKey , equalSQL , value )
2018-02-11 10:52:52 +03:00
case [ ] int , [ ] int8 , [ ] int16 , [ ] int32 , [ ] int64 , [ ] uint , [ ] uint8 , [ ] uint16 , [ ] uint32 , [ ] uint64 , [ ] string , [ ] interface { } :
2018-02-11 18:52:38 +03:00
if ! include && reflect . ValueOf ( value ) . Len ( ) == 0 {
return
}
str = fmt . Sprintf ( "(%v.%v %s (?))" , quotedTableName , quotedPrimaryKey , inSQL )
2018-02-11 10:52:52 +03:00
clause [ "args" ] = [ ] interface { } { value }
2016-03-08 16:45:20 +03:00
case string :
2016-12-20 06:36:13 +03:00
if isNumberRegexp . MatchString ( value ) {
2018-02-11 18:52:38 +03:00
return fmt . Sprintf ( "(%v.%v %s %v)" , quotedTableName , quotedPrimaryKey , equalSQL , scope . AddToVars ( value ) )
2016-03-08 16:45:20 +03:00
}
2018-02-11 18:52:38 +03:00
if value != "" {
if ! include {
if comparisonRegexp . MatchString ( value ) {
str = fmt . Sprintf ( "NOT (%v)" , value )
} else {
str = fmt . Sprintf ( "(%v.%v NOT IN (?))" , quotedTableName , scope . Quote ( value ) )
2016-03-08 16:45:20 +03:00
}
} else {
2018-02-11 18:52:38 +03:00
str = fmt . Sprintf ( "(%v)" , value )
2016-03-08 16:45:20 +03:00
}
2018-02-11 10:52:52 +03:00
}
2016-03-08 16:45:20 +03:00
case map [ string ] interface { } :
var sqls [ ] string
for key , value := range value {
if value != nil {
2018-02-11 18:52:38 +03:00
sqls = append ( sqls , fmt . Sprintf ( "(%v.%v %s %v)" , quotedTableName , scope . Quote ( key ) , equalSQL , scope . AddToVars ( value ) ) )
2016-03-08 16:45:20 +03:00
} else {
2018-02-11 18:52:38 +03:00
if ! include {
sqls = append ( sqls , fmt . Sprintf ( "(%v.%v IS NOT NULL)" , quotedTableName , scope . Quote ( key ) ) )
} else {
sqls = append ( sqls , fmt . Sprintf ( "(%v.%v IS NULL)" , quotedTableName , scope . Quote ( key ) ) )
}
2016-03-08 16:45:20 +03:00
}
}
return strings . Join ( sqls , " AND " )
case interface { } :
var sqls [ ] string
2018-02-11 18:52:38 +03:00
newScope := scope . New ( value )
2018-02-12 08:09:37 +03:00
if len ( newScope . Fields ( ) ) == 0 {
scope . Err ( fmt . Errorf ( "invalid query condition: %v" , value ) )
return
}
2018-08-19 02:13:16 +03:00
scopeQuotedTableName := newScope . QuotedTableName ( )
2016-08-13 16:23:18 +03:00
for _ , field := range newScope . Fields ( ) {
2018-02-11 10:52:52 +03:00
if ! field . IsIgnored && ! field . IsBlank {
2018-08-19 02:13:16 +03:00
sqls = append ( sqls , fmt . Sprintf ( "(%v.%v %s %v)" , scopeQuotedTableName , scope . Quote ( field . DBName ) , equalSQL , scope . AddToVars ( field . Field . Interface ( ) ) ) )
2016-03-08 16:45:20 +03:00
}
}
return strings . Join ( sqls , " AND " )
2018-02-12 08:09:37 +03:00
default :
scope . Err ( fmt . Errorf ( "invalid query condition: %v" , value ) )
return
2016-03-08 16:45:20 +03:00
}
2018-02-11 10:52:52 +03:00
replacements := [ ] string { }
2016-03-08 16:45:20 +03:00
args := clause [ "args" ] . ( [ ] interface { } )
for _ , arg := range args {
2017-08-30 22:52:45 +03:00
var err error
2018-02-11 07:48:08 +03:00
switch reflect . ValueOf ( arg ) . Kind ( ) {
case reflect . Slice : // For where("id in (?)", []int64{1,2})
if scanner , ok := interface { } ( arg ) . ( driver . Valuer ) ; ok {
arg , err = scanner . Value ( )
2018-02-11 10:52:52 +03:00
replacements = append ( replacements , scope . AddToVars ( arg ) )
2017-10-23 05:50:44 +03:00
} else if b , ok := arg . ( [ ] byte ) ; ok {
2018-02-11 10:52:52 +03:00
replacements = append ( replacements , scope . AddToVars ( b ) )
2018-02-13 03:32:22 +03:00
} else if as , ok := arg . ( [ ] [ ] interface { } ) ; ok {
var tempMarks [ ] string
for _ , a := range as {
var arrayMarks [ ] string
for _ , v := range a {
arrayMarks = append ( arrayMarks , scope . AddToVars ( v ) )
}
if len ( arrayMarks ) > 0 {
tempMarks = append ( tempMarks , fmt . Sprintf ( "(%v)" , strings . Join ( arrayMarks , "," ) ) )
}
}
if len ( tempMarks ) > 0 {
replacements = append ( replacements , strings . Join ( tempMarks , "," ) )
}
2018-02-11 07:48:08 +03:00
} else if values := reflect . ValueOf ( arg ) ; values . Len ( ) > 0 {
var tempMarks [ ] string
for i := 0 ; i < values . Len ( ) ; i ++ {
tempMarks = append ( tempMarks , scope . AddToVars ( values . Index ( i ) . Interface ( ) ) )
2016-03-08 16:45:20 +03:00
}
2018-02-11 10:52:52 +03:00
replacements = append ( replacements , strings . Join ( tempMarks , "," ) )
2016-03-08 16:45:20 +03:00
} else {
2018-02-11 10:52:52 +03:00
replacements = append ( replacements , scope . AddToVars ( Expr ( "NULL" ) ) )
2016-03-08 16:45:20 +03:00
}
2018-02-11 07:48:08 +03:00
default :
2018-02-11 18:52:38 +03:00
if valuer , ok := interface { } ( arg ) . ( driver . Valuer ) ; ok {
arg , err = valuer . Value ( )
2016-03-08 16:45:20 +03:00
}
2018-02-11 10:52:52 +03:00
replacements = append ( replacements , scope . AddToVars ( arg ) )
2016-03-08 16:45:20 +03:00
}
2018-02-11 10:52:52 +03:00
2018-02-11 07:48:08 +03:00
if err != nil {
scope . Err ( err )
}
2016-03-08 16:45:20 +03:00
}
2018-02-11 10:52:52 +03:00
buff := bytes . NewBuffer ( [ ] byte { } )
i := 0
2018-02-13 07:37:39 +03:00
for _ , s := range str {
2018-02-28 02:43:56 +03:00
if s == '?' && len ( replacements ) > i {
2018-02-11 10:52:52 +03:00
buff . WriteString ( replacements [ i ] )
i ++
} else {
2018-02-13 07:37:39 +03:00
buff . WriteRune ( s )
2018-02-11 10:52:52 +03:00
}
}
str = buff . String ( )
2018-02-11 18:52:38 +03:00
2016-03-08 16:45:20 +03:00
return
}
func ( scope * Scope ) buildSelectQuery ( clause map [ string ] interface { } ) ( str string ) {
switch value := clause [ "query" ] . ( type ) {
case string :
str = value
case [ ] string :
str = strings . Join ( value , ", " )
}
args := clause [ "args" ] . ( [ ] interface { } )
2017-10-23 05:50:44 +03:00
replacements := [ ] string { }
2016-03-08 16:45:20 +03:00
for _ , arg := range args {
2018-02-11 07:48:08 +03:00
switch reflect . ValueOf ( arg ) . Kind ( ) {
case reflect . Slice :
values := reflect . ValueOf ( arg )
var tempMarks [ ] string
for i := 0 ; i < values . Len ( ) ; i ++ {
tempMarks = append ( tempMarks , scope . AddToVars ( values . Index ( i ) . Interface ( ) ) )
2016-03-08 16:45:20 +03:00
}
2017-10-23 05:50:44 +03:00
replacements = append ( replacements , strings . Join ( tempMarks , "," ) )
2018-02-11 07:48:08 +03:00
default :
if valuer , ok := interface { } ( arg ) . ( driver . Valuer ) ; ok {
arg , _ = valuer . Value ( )
2016-03-08 16:45:20 +03:00
}
2017-10-23 05:50:44 +03:00
replacements = append ( replacements , scope . AddToVars ( arg ) )
2016-03-08 16:45:20 +03:00
}
}
2017-10-23 05:50:44 +03:00
buff := bytes . NewBuffer ( [ ] byte { } )
i := 0
2018-03-15 17:35:31 +03:00
for pos , char := range str {
2017-10-23 05:50:44 +03:00
if str [ pos ] == '?' {
buff . WriteString ( replacements [ i ] )
i ++
} else {
2018-03-15 17:35:31 +03:00
buff . WriteRune ( char )
2017-10-23 05:50:44 +03:00
}
}
str = buff . String ( )
2016-03-08 16:45:20 +03:00
return
}
func ( scope * Scope ) whereSQL ( ) ( sql string ) {
var (
quotedTableName = scope . QuotedTableName ( )
2017-02-01 16:33:36 +03:00
deletedAtField , hasDeletedAtField = scope . FieldByName ( "DeletedAt" )
2016-03-08 16:45:20 +03:00
primaryConditions , andConditions , orConditions [ ] string
)
2017-02-01 16:33:36 +03:00
if ! scope . Search . Unscoped && hasDeletedAtField {
sql := fmt . Sprintf ( "%v.%v IS NULL" , quotedTableName , scope . Quote ( deletedAtField . DBName ) )
2016-03-08 16:45:20 +03:00
primaryConditions = append ( primaryConditions , sql )
}
if ! scope . PrimaryKeyZero ( ) {
for _ , field := range scope . PrimaryFields ( ) {
sql := fmt . Sprintf ( "%v.%v = %v" , quotedTableName , scope . Quote ( field . DBName ) , scope . AddToVars ( field . Field . Interface ( ) ) )
primaryConditions = append ( primaryConditions , sql )
}
}
for _ , clause := range scope . Search . whereConditions {
2018-02-11 18:52:38 +03:00
if sql := scope . buildCondition ( clause , true ) ; sql != "" {
2016-03-08 16:45:20 +03:00
andConditions = append ( andConditions , sql )
}
}
for _ , clause := range scope . Search . orConditions {
2018-02-11 18:52:38 +03:00
if sql := scope . buildCondition ( clause , true ) ; sql != "" {
2016-03-08 16:45:20 +03:00
orConditions = append ( orConditions , sql )
}
}
for _ , clause := range scope . Search . notConditions {
2018-02-11 18:52:38 +03:00
if sql := scope . buildCondition ( clause , false ) ; sql != "" {
2016-03-08 16:45:20 +03:00
andConditions = append ( andConditions , sql )
}
}
orSQL := strings . Join ( orConditions , " OR " )
combinedSQL := strings . Join ( andConditions , " AND " )
if len ( combinedSQL ) > 0 {
if len ( orSQL ) > 0 {
combinedSQL = combinedSQL + " OR " + orSQL
}
} else {
combinedSQL = orSQL
}
if len ( primaryConditions ) > 0 {
sql = "WHERE " + strings . Join ( primaryConditions , " AND " )
if len ( combinedSQL ) > 0 {
sql = sql + " AND (" + combinedSQL + ")"
}
} else if len ( combinedSQL ) > 0 {
sql = "WHERE " + combinedSQL
}
return
}
func ( scope * Scope ) selectSQL ( ) string {
if len ( scope . Search . selects ) == 0 {
2016-03-14 03:05:36 +03:00
if len ( scope . Search . joinConditions ) > 0 {
return fmt . Sprintf ( "%v.*" , scope . QuotedTableName ( ) )
}
2016-03-08 16:45:20 +03:00
return "*"
}
return scope . buildSelectQuery ( scope . Search . selects )
}
func ( scope * Scope ) orderSQL ( ) string {
2016-12-01 11:16:20 +03:00
if len ( scope . Search . orders ) == 0 || scope . Search . ignoreOrderQuery {
2016-03-08 16:45:20 +03:00
return ""
}
2016-03-23 05:29:52 +03:00
var orders [ ] string
for _ , order := range scope . Search . orders {
2016-06-28 06:15:42 +03:00
if str , ok := order . ( string ) ; ok {
orders = append ( orders , scope . quoteIfPossible ( str ) )
2019-10-17 18:44:34 +03:00
} else if expr , ok := order . ( * SqlExpr ) ; ok {
2016-06-28 06:15:42 +03:00
exp := expr . expr
for _ , arg := range expr . args {
exp = strings . Replace ( exp , "?" , scope . AddToVars ( arg ) , 1 )
}
orders = append ( orders , exp )
}
2016-03-23 05:29:52 +03:00
}
return " ORDER BY " + strings . Join ( orders , "," )
2016-03-08 16:45:20 +03:00
}
func ( scope * Scope ) limitAndOffsetSQL ( ) string {
2019-10-30 20:51:26 +03:00
sql , err := scope . Dialect ( ) . LimitAndOffsetSQL ( scope . Search . limit , scope . Search . offset )
scope . Err ( err )
return sql
2016-03-08 16:45:20 +03:00
}
func ( scope * Scope ) groupSQL ( ) string {
if len ( scope . Search . group ) == 0 {
return ""
}
return " GROUP BY " + scope . Search . group
}
func ( scope * Scope ) havingSQL ( ) string {
if len ( scope . Search . havingConditions ) == 0 {
return ""
}
var andConditions [ ] string
for _ , clause := range scope . Search . havingConditions {
2018-02-11 18:52:38 +03:00
if sql := scope . buildCondition ( clause , true ) ; sql != "" {
2016-03-08 16:45:20 +03:00
andConditions = append ( andConditions , sql )
}
}
combinedSQL := strings . Join ( andConditions , " AND " )
if len ( combinedSQL ) == 0 {
return ""
}
return " HAVING " + combinedSQL
}
func ( scope * Scope ) joinsSQL ( ) string {
var joinConditions [ ] string
for _ , clause := range scope . Search . joinConditions {
2018-02-11 18:52:38 +03:00
if sql := scope . buildCondition ( clause , true ) ; sql != "" {
2016-03-08 16:45:20 +03:00
joinConditions = append ( joinConditions , strings . TrimSuffix ( strings . TrimPrefix ( sql , "(" ) , ")" ) )
}
}
return strings . Join ( joinConditions , " " ) + " "
}
func ( scope * Scope ) prepareQuerySQL ( ) {
if scope . Search . raw {
2016-10-26 17:30:20 +03:00
scope . Raw ( scope . CombinedConditionSql ( ) )
2016-03-08 16:45:20 +03:00
} else {
scope . Raw ( fmt . Sprintf ( "SELECT %v FROM %v %v" , scope . selectSQL ( ) , scope . QuotedTableName ( ) , scope . CombinedConditionSql ( ) ) )
}
return
}
func ( scope * Scope ) inlineCondition ( values ... interface { } ) * Scope {
if len ( values ) > 0 {
scope . Search . Where ( values [ 0 ] , values [ 1 : ] ... )
}
return scope
}
func ( scope * Scope ) callCallbacks ( funcs [ ] * func ( s * Scope ) ) * Scope {
2018-09-14 10:53:49 +03:00
defer func ( ) {
if err := recover ( ) ; err != nil {
if db , ok := scope . db . db . ( sqlTx ) ; ok {
db . Rollback ( )
}
panic ( err )
}
} ( )
2016-03-08 16:45:20 +03:00
for _ , f := range funcs {
( * f ) ( scope )
if scope . skipLeft {
break
}
}
return scope
}
2019-05-05 12:12:03 +03:00
func convertInterfaceToMap ( values interface { } , withIgnoredField bool , db * DB ) map [ string ] interface { } {
2016-03-09 11:18:01 +03:00
var attrs = map [ string ] interface { } { }
switch value := values . ( type ) {
case map [ string ] interface { } :
return value
case [ ] interface { } :
for _ , v := range value {
2019-05-05 12:12:03 +03:00
for key , value := range convertInterfaceToMap ( v , withIgnoredField , db ) {
2016-03-09 11:18:01 +03:00
attrs [ key ] = value
}
}
case interface { } :
reflectValue := reflect . ValueOf ( values )
switch reflectValue . Kind ( ) {
case reflect . Map :
for _ , key := range reflectValue . MapKeys ( ) {
2018-09-10 00:52:20 +03:00
attrs [ ToColumnName ( key . Interface ( ) . ( string ) ) ] = reflectValue . MapIndex ( key ) . Interface ( )
2016-03-09 11:18:01 +03:00
}
default :
2019-05-05 12:12:03 +03:00
for _ , field := range ( & Scope { Value : values , db : db } ) . Fields ( ) {
2016-08-14 11:10:30 +03:00
if ! field . IsBlank && ( withIgnoredField || ! field . IsIgnored ) {
2016-03-09 11:18:01 +03:00
attrs [ field . DBName ] = field . Field . Interface ( )
}
}
}
}
return attrs
}
func ( scope * Scope ) updatedAttrsWithValues ( value interface { } ) ( results map [ string ] interface { } , hasUpdate bool ) {
2016-03-08 16:45:20 +03:00
if scope . IndirectValue ( ) . Kind ( ) != reflect . Struct {
2019-05-05 12:12:03 +03:00
return convertInterfaceToMap ( value , false , scope . db ) , true
2016-03-08 16:45:20 +03:00
}
results = map [ string ] interface { } { }
2016-03-09 11:18:01 +03:00
2019-05-05 12:12:03 +03:00
for key , value := range convertInterfaceToMap ( value , true , scope . db ) {
2016-03-08 16:45:20 +03:00
if field , ok := scope . FieldByName ( key ) ; ok && scope . changeableField ( field ) {
2019-10-17 18:44:34 +03:00
if _ , ok := value . ( * SqlExpr ) ; ok {
2016-03-09 11:18:01 +03:00
hasUpdate = true
results [ field . DBName ] = value
2016-03-08 16:45:20 +03:00
} else {
2016-04-04 16:33:11 +03:00
err := field . Set ( value )
2018-09-10 01:03:41 +03:00
if field . IsNormal && ! field . IsIgnored {
2016-03-09 11:18:01 +03:00
hasUpdate = true
2016-04-04 16:33:11 +03:00
if err == ErrUnaddressable {
results [ field . DBName ] = value
} else {
results [ field . DBName ] = field . Field . Interface ( )
}
2016-03-09 11:18:01 +03:00
}
2016-03-08 16:45:20 +03:00
}
}
}
return
}
func ( scope * Scope ) row ( ) * sql . Row {
2019-06-10 15:45:42 +03:00
defer scope . trace ( scope . db . nowFunc ( ) )
2017-01-15 13:03:12 +03:00
result := & RowQueryResult { }
scope . InstanceSet ( "row_query_result" , result )
2016-03-08 16:45:20 +03:00
scope . callCallbacks ( scope . db . parent . callbacks . rowQueries )
2017-01-15 13:03:12 +03:00
return result . Row
2016-03-08 16:45:20 +03:00
}
func ( scope * Scope ) rows ( ) ( * sql . Rows , error ) {
2019-06-10 15:45:42 +03:00
defer scope . trace ( scope . db . nowFunc ( ) )
2017-01-15 13:03:12 +03:00
result := & RowsQueryResult { }
scope . InstanceSet ( "row_query_result" , result )
2016-03-08 16:45:20 +03:00
scope . callCallbacks ( scope . db . parent . callbacks . rowQueries )
2017-01-15 13:03:12 +03:00
return result . Rows , result . Error
2016-03-08 16:45:20 +03:00
}
func ( scope * Scope ) initialize ( ) * Scope {
for _ , clause := range scope . Search . whereConditions {
2016-03-09 11:18:01 +03:00
scope . updatedAttrsWithValues ( clause [ "query" ] )
2016-03-08 16:45:20 +03:00
}
2016-03-09 11:18:01 +03:00
scope . updatedAttrsWithValues ( scope . Search . initAttrs )
scope . updatedAttrsWithValues ( scope . Search . assignAttrs )
2016-03-08 16:45:20 +03:00
return scope
}
2017-08-14 21:46:39 +03:00
func ( scope * Scope ) isQueryForColumn ( query interface { } , column string ) bool {
2017-09-04 19:12:20 +03:00
queryStr := strings . ToLower ( fmt . Sprint ( query ) )
2017-08-14 21:46:39 +03:00
if queryStr == column {
return true
}
2017-09-04 19:12:20 +03:00
if strings . HasSuffix ( queryStr , "as " + column ) {
return true
}
2018-02-11 08:41:46 +03:00
if strings . HasSuffix ( queryStr , "as " + scope . Quote ( column ) ) {
2017-08-14 21:46:39 +03:00
return true
}
return false
}
2016-03-08 16:45:20 +03:00
func ( scope * Scope ) pluck ( column string , value interface { } ) * Scope {
dest := reflect . Indirect ( reflect . ValueOf ( value ) )
if dest . Kind ( ) != reflect . Slice {
scope . Err ( fmt . Errorf ( "results should be a slice, not %s" , dest . Kind ( ) ) )
return scope
}
2019-04-19 14:41:30 +03:00
if dest . Len ( ) > 0 {
dest . Set ( reflect . Zero ( dest . Type ( ) ) )
}
2017-08-14 21:46:39 +03:00
if query , ok := scope . Search . selects [ "query" ] ; ! ok || ! scope . isQueryForColumn ( query , column ) {
scope . Search . Select ( column )
}
2016-03-08 16:45:20 +03:00
rows , err := scope . rows ( )
if scope . Err ( err ) == nil {
defer rows . Close ( )
for rows . Next ( ) {
elem := reflect . New ( dest . Type ( ) . Elem ( ) ) . Interface ( )
scope . Err ( rows . Scan ( elem ) )
dest . Set ( reflect . Append ( dest , reflect . ValueOf ( elem ) . Elem ( ) ) )
}
2017-03-24 04:28:06 +03:00
if err := rows . Err ( ) ; err != nil {
scope . Err ( err )
}
2016-03-08 16:45:20 +03:00
}
return scope
}
func ( scope * Scope ) count ( value interface { } ) * Scope {
2016-12-20 06:36:13 +03:00
if query , ok := scope . Search . selects [ "query" ] ; ! ok || ! countingQueryRegexp . MatchString ( fmt . Sprint ( query ) ) {
2017-08-29 13:50:40 +03:00
if len ( scope . Search . group ) != 0 {
2019-03-11 14:56:03 +03:00
if len ( scope . Search . havingConditions ) != 0 {
scope . prepareQuerySQL ( )
scope . Search = & search { }
scope . Search . Select ( "count(*)" )
scope . Search . Table ( fmt . Sprintf ( "( %s ) AS count_table" , scope . SQL ) )
} else {
scope . Search . Select ( "count(*) FROM ( SELECT count(*) as name " )
scope . Search . group += " ) AS count_table"
}
2017-08-29 13:50:40 +03:00
} else {
scope . Search . Select ( "count(*)" )
}
2016-08-14 10:15:09 +03:00
}
2016-12-01 11:16:20 +03:00
scope . Search . ignoreOrderQuery = true
2016-03-08 16:45:20 +03:00
scope . Err ( scope . row ( ) . Scan ( value ) )
return scope
}
func ( scope * Scope ) typeName ( ) string {
typ := scope . IndirectValue ( ) . Type ( )
for typ . Kind ( ) == reflect . Slice || typ . Kind ( ) == reflect . Ptr {
typ = typ . Elem ( )
}
return typ . Name ( )
}
// trace print sql log
func ( scope * Scope ) trace ( t time . Time ) {
if len ( scope . SQL ) > 0 {
scope . db . slog ( scope . SQL , t , scope . SQLVars ... )
}
}
func ( scope * Scope ) changeableField ( field * Field ) bool {
if selectAttrs := scope . SelectAttrs ( ) ; len ( selectAttrs ) > 0 {
for _ , attr := range selectAttrs {
if field . Name == attr || field . DBName == attr {
return true
}
}
return false
}
for _ , attr := range scope . OmitAttrs ( ) {
if field . Name == attr || field . DBName == attr {
return false
}
}
return true
}
func ( scope * Scope ) related ( value interface { } , foreignKeys ... string ) * Scope {
toScope := scope . db . NewScope ( value )
2016-12-05 13:30:07 +03:00
tx := scope . db . Set ( "gorm:association:source" , scope . Value )
2016-03-08 16:45:20 +03:00
for _ , foreignKey := range append ( foreignKeys , toScope . typeName ( ) + "Id" , scope . typeName ( ) + "Id" ) {
fromField , _ := scope . FieldByName ( foreignKey )
toField , _ := toScope . FieldByName ( foreignKey )
if fromField != nil {
if relationship := fromField . Relationship ; relationship != nil {
if relationship . Kind == "many_to_many" {
joinTableHandler := relationship . JoinTableHandler
2016-12-05 13:30:07 +03:00
scope . Err ( joinTableHandler . JoinWith ( joinTableHandler , tx , scope . Value ) . Find ( value ) . Error )
2016-03-08 16:45:20 +03:00
} else if relationship . Kind == "belongs_to" {
for idx , foreignKey := range relationship . ForeignDBNames {
if field , ok := scope . FieldByName ( foreignKey ) ; ok {
2016-12-05 13:30:07 +03:00
tx = tx . Where ( fmt . Sprintf ( "%v = ?" , scope . Quote ( relationship . AssociationForeignDBNames [ idx ] ) ) , field . Field . Interface ( ) )
2016-03-08 16:45:20 +03:00
}
}
2016-12-05 13:30:07 +03:00
scope . Err ( tx . Find ( value ) . Error )
2016-03-08 16:45:20 +03:00
} else if relationship . Kind == "has_many" || relationship . Kind == "has_one" {
for idx , foreignKey := range relationship . ForeignDBNames {
if field , ok := scope . FieldByName ( relationship . AssociationForeignDBNames [ idx ] ) ; ok {
2016-12-05 13:30:07 +03:00
tx = tx . Where ( fmt . Sprintf ( "%v = ?" , scope . Quote ( foreignKey ) ) , field . Field . Interface ( ) )
2016-03-08 16:45:20 +03:00
}
}
if relationship . PolymorphicType != "" {
2016-12-05 13:30:07 +03:00
tx = tx . Where ( fmt . Sprintf ( "%v = ?" , scope . Quote ( relationship . PolymorphicDBName ) ) , relationship . PolymorphicValue )
2016-03-08 16:45:20 +03:00
}
2016-12-05 13:30:07 +03:00
scope . Err ( tx . Find ( value ) . Error )
2016-03-08 16:45:20 +03:00
}
} else {
sql := fmt . Sprintf ( "%v = ?" , scope . Quote ( toScope . PrimaryKey ( ) ) )
2016-12-05 13:30:07 +03:00
scope . Err ( tx . Where ( sql , fromField . Field . Interface ( ) ) . Find ( value ) . Error )
2016-03-08 16:45:20 +03:00
}
return scope
} else if toField != nil {
sql := fmt . Sprintf ( "%v = ?" , scope . Quote ( toField . DBName ) )
2016-12-05 13:30:07 +03:00
scope . Err ( tx . Where ( sql , scope . PrimaryKeyValue ( ) ) . Find ( value ) . Error )
2016-03-08 16:45:20 +03:00
return scope
}
}
scope . Err ( fmt . Errorf ( "invalid association %v" , foreignKeys ) )
return scope
}
// getTableOptions return the table options string or an empty string if the table options does not exist
func ( scope * Scope ) getTableOptions ( ) string {
tableOptions , ok := scope . Get ( "gorm:table_options" )
if ! ok {
return ""
}
2018-02-12 09:48:11 +03:00
return " " + tableOptions . ( string )
2016-03-08 16:45:20 +03:00
}
func ( scope * Scope ) createJoinTable ( field * StructField ) {
if relationship := field . Relationship ; relationship != nil && relationship . JoinTableHandler != nil {
joinTableHandler := relationship . JoinTableHandler
joinTable := joinTableHandler . Table ( scope . db )
if ! scope . Dialect ( ) . HasTable ( joinTable ) {
toScope := & Scope { Value : reflect . New ( field . Struct . Type ) . Interface ( ) }
var sqlTypes , primaryKeys [ ] string
for idx , fieldName := range relationship . ForeignFieldNames {
if field , ok := scope . FieldByName ( fieldName ) ; ok {
foreignKeyStruct := field . clone ( )
foreignKeyStruct . IsPrimaryKey = false
2018-09-10 02:11:00 +03:00
foreignKeyStruct . TagSettingsSet ( "IS_JOINTABLE_FOREIGNKEY" , "true" )
foreignKeyStruct . TagSettingsDelete ( "AUTO_INCREMENT" )
2016-03-08 16:45:20 +03:00
sqlTypes = append ( sqlTypes , scope . Quote ( relationship . ForeignDBNames [ idx ] ) + " " + scope . Dialect ( ) . DataTypeOf ( foreignKeyStruct ) )
primaryKeys = append ( primaryKeys , scope . Quote ( relationship . ForeignDBNames [ idx ] ) )
}
}
for idx , fieldName := range relationship . AssociationForeignFieldNames {
if field , ok := toScope . FieldByName ( fieldName ) ; ok {
foreignKeyStruct := field . clone ( )
foreignKeyStruct . IsPrimaryKey = false
2018-09-10 02:11:00 +03:00
foreignKeyStruct . TagSettingsSet ( "IS_JOINTABLE_FOREIGNKEY" , "true" )
foreignKeyStruct . TagSettingsDelete ( "AUTO_INCREMENT" )
2016-03-08 16:45:20 +03:00
sqlTypes = append ( sqlTypes , scope . Quote ( relationship . AssociationForeignDBNames [ idx ] ) + " " + scope . Dialect ( ) . DataTypeOf ( foreignKeyStruct ) )
primaryKeys = append ( primaryKeys , scope . Quote ( relationship . AssociationForeignDBNames [ idx ] ) )
}
}
2018-02-12 09:48:11 +03:00
scope . Err ( scope . NewDB ( ) . Exec ( fmt . Sprintf ( "CREATE TABLE %v (%v, PRIMARY KEY (%v))%s" , scope . Quote ( joinTable ) , strings . Join ( sqlTypes , "," ) , strings . Join ( primaryKeys , "," ) , scope . getTableOptions ( ) ) ) . Error )
2016-03-08 16:45:20 +03:00
}
scope . NewDB ( ) . Table ( joinTable ) . AutoMigrate ( joinTableHandler )
}
}
func ( scope * Scope ) createTable ( ) * Scope {
var tags [ ] string
var primaryKeys [ ] string
var primaryKeyInColumnType = false
for _ , field := range scope . GetModelStruct ( ) . StructFields {
if field . IsNormal {
sqlTag := scope . Dialect ( ) . DataTypeOf ( field )
// Check if the primary key constraint was specified as
// part of the column type. If so, we can only support
// one column as the primary key.
if strings . Contains ( strings . ToLower ( sqlTag ) , "primary key" ) {
primaryKeyInColumnType = true
}
tags = append ( tags , scope . Quote ( field . DBName ) + " " + sqlTag )
}
if field . IsPrimaryKey {
primaryKeys = append ( primaryKeys , scope . Quote ( field . DBName ) )
}
scope . createJoinTable ( field )
}
var primaryKeyStr string
if len ( primaryKeys ) > 0 && ! primaryKeyInColumnType {
primaryKeyStr = fmt . Sprintf ( ", PRIMARY KEY (%v)" , strings . Join ( primaryKeys , "," ) )
}
2018-02-12 09:48:11 +03:00
scope . Raw ( fmt . Sprintf ( "CREATE TABLE %v (%v %v)%s" , scope . QuotedTableName ( ) , strings . Join ( tags , "," ) , primaryKeyStr , scope . getTableOptions ( ) ) ) . Exec ( )
2016-03-08 16:45:20 +03:00
scope . autoIndex ( )
return scope
}
func ( scope * Scope ) dropTable ( ) * Scope {
2019-05-08 09:23:31 +03:00
scope . Raw ( fmt . Sprintf ( "DROP TABLE %v" , scope . QuotedTableName ( ) ) ) . Exec ( )
2016-03-08 16:45:20 +03:00
return scope
}
func ( scope * Scope ) modifyColumn ( column string , typ string ) {
2018-02-09 17:58:34 +03:00
scope . db . AddError ( scope . Dialect ( ) . ModifyColumn ( scope . QuotedTableName ( ) , scope . Quote ( column ) , typ ) )
2016-03-08 16:45:20 +03:00
}
func ( scope * Scope ) dropColumn ( column string ) {
scope . Raw ( fmt . Sprintf ( "ALTER TABLE %v DROP COLUMN %v" , scope . QuotedTableName ( ) , scope . Quote ( column ) ) ) . Exec ( )
}
func ( scope * Scope ) addIndex ( unique bool , indexName string , column ... string ) {
if scope . Dialect ( ) . HasIndex ( scope . TableName ( ) , indexName ) {
return
}
var columns [ ] string
for _ , name := range column {
columns = append ( columns , scope . quoteIfPossible ( name ) )
}
sqlCreate := "CREATE INDEX"
if unique {
sqlCreate = "CREATE UNIQUE INDEX"
}
scope . Raw ( fmt . Sprintf ( "%s %v ON %v(%v) %v" , sqlCreate , indexName , scope . QuotedTableName ( ) , strings . Join ( columns , ", " ) , scope . whereSQL ( ) ) ) . Exec ( )
}
func ( scope * Scope ) addForeignKey ( field string , dest string , onDelete string , onUpdate string ) {
2018-02-02 17:01:31 +03:00
// Compatible with old generated key
keyName := scope . Dialect ( ) . BuildKeyName ( scope . TableName ( ) , field , dest , "foreign" )
2016-03-08 16:45:20 +03:00
if scope . Dialect ( ) . HasForeignKey ( scope . TableName ( ) , keyName ) {
return
}
var query = ` ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s ON DELETE %s ON UPDATE %s; `
scope . Raw ( fmt . Sprintf ( query , scope . QuotedTableName ( ) , scope . quoteIfPossible ( keyName ) , scope . quoteIfPossible ( field ) , dest , onDelete , onUpdate ) ) . Exec ( )
}
2018-02-09 17:20:26 +03:00
func ( scope * Scope ) removeForeignKey ( field string , dest string ) {
2018-04-16 17:20:02 +03:00
keyName := scope . Dialect ( ) . BuildKeyName ( scope . TableName ( ) , field , dest , "foreign" )
2018-02-09 17:20:26 +03:00
if ! scope . Dialect ( ) . HasForeignKey ( scope . TableName ( ) , keyName ) {
return
}
2018-07-27 02:43:49 +03:00
var mysql mysql
var query string
if scope . Dialect ( ) . GetName ( ) == mysql . GetName ( ) {
query = ` ALTER TABLE %s DROP FOREIGN KEY %s; `
} else {
query = ` ALTER TABLE %s DROP CONSTRAINT %s; `
}
2018-02-09 17:20:26 +03:00
scope . Raw ( fmt . Sprintf ( query , scope . QuotedTableName ( ) , scope . quoteIfPossible ( keyName ) ) ) . Exec ( )
}
2016-03-08 16:45:20 +03:00
func ( scope * Scope ) removeIndex ( indexName string ) {
scope . Dialect ( ) . RemoveIndex ( scope . TableName ( ) , indexName )
}
func ( scope * Scope ) autoMigrate ( ) * Scope {
tableName := scope . TableName ( )
quotedTableName := scope . QuotedTableName ( )
if ! scope . Dialect ( ) . HasTable ( tableName ) {
scope . createTable ( )
} else {
for _ , field := range scope . GetModelStruct ( ) . StructFields {
if ! scope . Dialect ( ) . HasColumn ( tableName , field . DBName ) {
if field . IsNormal {
sqlTag := scope . Dialect ( ) . DataTypeOf ( field )
scope . Raw ( fmt . Sprintf ( "ALTER TABLE %v ADD %v %v;" , quotedTableName , scope . Quote ( field . DBName ) , sqlTag ) ) . Exec ( )
}
}
scope . createJoinTable ( field )
}
scope . autoIndex ( )
}
return scope
}
func ( scope * Scope ) autoIndex ( ) * Scope {
var indexes = map [ string ] [ ] string { }
var uniqueIndexes = map [ string ] [ ] string { }
for _ , field := range scope . GetStructFields ( ) {
2018-09-10 02:11:00 +03:00
if name , ok := field . TagSettingsGet ( "INDEX" ) ; ok {
2016-06-16 02:06:22 +03:00
names := strings . Split ( name , "," )
for _ , name := range names {
if name == "INDEX" || name == "" {
2018-02-02 17:01:31 +03:00
name = scope . Dialect ( ) . BuildKeyName ( "idx" , scope . TableName ( ) , field . DBName )
2016-06-16 02:06:22 +03:00
}
2019-04-15 11:46:50 +03:00
name , column := scope . Dialect ( ) . NormalizeIndexAndColumn ( name , field . DBName )
indexes [ name ] = append ( indexes [ name ] , column )
2016-03-08 16:45:20 +03:00
}
}
2018-09-10 02:11:00 +03:00
if name , ok := field . TagSettingsGet ( "UNIQUE_INDEX" ) ; ok {
2016-06-16 02:06:22 +03:00
names := strings . Split ( name , "," )
for _ , name := range names {
if name == "UNIQUE_INDEX" || name == "" {
2018-02-02 17:01:31 +03:00
name = scope . Dialect ( ) . BuildKeyName ( "uix" , scope . TableName ( ) , field . DBName )
2016-06-16 02:06:22 +03:00
}
2019-04-15 11:46:50 +03:00
name , column := scope . Dialect ( ) . NormalizeIndexAndColumn ( name , field . DBName )
uniqueIndexes [ name ] = append ( uniqueIndexes [ name ] , column )
2016-03-08 16:45:20 +03:00
}
}
}
for name , columns := range indexes {
2018-02-12 06:56:45 +03:00
if db := scope . NewDB ( ) . Table ( scope . TableName ( ) ) . Model ( scope . Value ) . AddIndex ( name , columns ... ) ; db . Error != nil {
2018-01-31 12:14:21 +03:00
scope . db . AddError ( db . Error )
2017-11-28 08:05:10 +03:00
}
2016-03-08 16:45:20 +03:00
}
for name , columns := range uniqueIndexes {
2018-02-12 06:56:45 +03:00
if db := scope . NewDB ( ) . Table ( scope . TableName ( ) ) . Model ( scope . Value ) . AddUniqueIndex ( name , columns ... ) ; db . Error != nil {
2018-01-31 12:14:21 +03:00
scope . db . AddError ( db . Error )
2017-11-28 08:05:10 +03:00
}
2016-03-08 16:45:20 +03:00
}
return scope
}
func ( scope * Scope ) getColumnAsArray ( columns [ ] string , values ... interface { } ) ( results [ ] [ ] interface { } ) {
2019-01-02 16:32:08 +03:00
resultMap := make ( map [ string ] [ ] interface { } )
2016-03-08 16:45:20 +03:00
for _ , value := range values {
2016-11-10 04:30:47 +03:00
indirectValue := indirect ( reflect . ValueOf ( value ) )
2016-03-08 16:45:20 +03:00
switch indirectValue . Kind ( ) {
case reflect . Slice :
for i := 0 ; i < indirectValue . Len ( ) ; i ++ {
var result [ ] interface { }
var object = indirect ( indirectValue . Index ( i ) )
2016-11-10 04:30:47 +03:00
var hasValue = false
2016-03-08 16:45:20 +03:00
for _ , column := range columns {
2016-11-10 04:30:47 +03:00
field := object . FieldByName ( column )
if hasValue || ! isBlank ( field ) {
hasValue = true
}
result = append ( result , field . Interface ( ) )
}
if hasValue {
2019-01-02 16:32:08 +03:00
h := fmt . Sprint ( result ... )
if _ , exist := resultMap [ h ] ; ! exist {
resultMap [ h ] = result
}
2016-03-08 16:45:20 +03:00
}
}
case reflect . Struct :
var result [ ] interface { }
2016-11-10 04:30:47 +03:00
var hasValue = false
2016-03-08 16:45:20 +03:00
for _ , column := range columns {
2016-11-10 04:30:47 +03:00
field := indirectValue . FieldByName ( column )
if hasValue || ! isBlank ( field ) {
hasValue = true
}
result = append ( result , field . Interface ( ) )
}
if hasValue {
2019-01-02 16:32:08 +03:00
h := fmt . Sprint ( result ... )
if _ , exist := resultMap [ h ] ; ! exist {
resultMap [ h ] = result
}
2016-03-08 16:45:20 +03:00
}
}
}
2019-01-02 16:32:08 +03:00
for _ , v := range resultMap {
results = append ( results , v )
}
2016-03-08 16:45:20 +03:00
return
}
func ( scope * Scope ) getColumnAsScope ( column string ) * Scope {
indirectScopeValue := scope . IndirectValue ( )
switch indirectScopeValue . Kind ( ) {
case reflect . Slice :
if fieldStruct , ok := scope . GetModelStruct ( ) . ModelType . FieldByName ( column ) ; ok {
fieldType := fieldStruct . Type
if fieldType . Kind ( ) == reflect . Slice || fieldType . Kind ( ) == reflect . Ptr {
fieldType = fieldType . Elem ( )
}
2016-07-10 16:34:37 +03:00
resultsMap := map [ interface { } ] bool { }
2016-03-08 16:45:20 +03:00
results := reflect . New ( reflect . SliceOf ( reflect . PtrTo ( fieldType ) ) ) . Elem ( )
for i := 0 ; i < indirectScopeValue . Len ( ) ; i ++ {
result := indirect ( indirect ( indirectScopeValue . Index ( i ) ) . FieldByName ( column ) )
if result . Kind ( ) == reflect . Slice {
for j := 0 ; j < result . Len ( ) ; j ++ {
2016-07-10 16:34:37 +03:00
if elem := result . Index ( j ) ; elem . CanAddr ( ) && resultsMap [ elem . Addr ( ) ] != true {
resultsMap [ elem . Addr ( ) ] = true
2016-03-08 16:45:20 +03:00
results = reflect . Append ( results , elem . Addr ( ) )
}
}
2016-07-10 16:34:37 +03:00
} else if result . CanAddr ( ) && resultsMap [ result . Addr ( ) ] != true {
resultsMap [ result . Addr ( ) ] = true
2016-03-08 16:45:20 +03:00
results = reflect . Append ( results , result . Addr ( ) )
}
}
return scope . New ( results . Interface ( ) )
}
case reflect . Struct :
if field := indirectScopeValue . FieldByName ( column ) ; field . CanAddr ( ) {
return scope . New ( field . Addr ( ) . Interface ( ) )
}
}
return nil
}
2016-11-04 19:41:31 +03:00
func ( scope * Scope ) hasConditions ( ) bool {
return ! scope . PrimaryKeyZero ( ) ||
len ( scope . Search . whereConditions ) > 0 ||
len ( scope . Search . orConditions ) > 0 ||
len ( scope . Search . notConditions ) > 0
}