1package gorm 2 3import ( 4 "bytes" 5 "database/sql" 6 "database/sql/driver" 7 "errors" 8 "fmt" 9 "reflect" 10 "regexp" 11 "strings" 12 "time" 13) 14 15// Scope contain current operation's information when you perform any operation on the database 16type Scope struct { 17 Search *search 18 Value interface{} 19 SQL string 20 SQLVars []interface{} 21 db *DB 22 instanceID string 23 primaryKeyField *Field 24 skipLeft bool 25 fields *[]*Field 26 selectAttrs *[]string 27} 28 29// IndirectValue return scope's reflect value's indirect value 30func (scope *Scope) IndirectValue() reflect.Value { 31 return indirect(reflect.ValueOf(scope.Value)) 32} 33 34// New create a new Scope without search information 35func (scope *Scope) New(value interface{}) *Scope { 36 return &Scope{db: scope.NewDB(), Search: &search{}, Value: value} 37} 38 39//////////////////////////////////////////////////////////////////////////////// 40// Scope DB 41//////////////////////////////////////////////////////////////////////////////// 42 43// DB return scope's DB connection 44func (scope *Scope) DB() *DB { 45 return scope.db 46} 47 48// NewDB create a new DB without search information 49func (scope *Scope) NewDB() *DB { 50 if scope.db != nil { 51 db := scope.db.clone() 52 db.search = nil 53 db.Value = nil 54 return db 55 } 56 return nil 57} 58 59// SQLDB return *sql.DB 60func (scope *Scope) SQLDB() SQLCommon { 61 return scope.db.db 62} 63 64// Dialect get dialect 65func (scope *Scope) Dialect() Dialect { 66 return scope.db.dialect 67} 68 69// Quote used to quote string to escape them for database 70func (scope *Scope) Quote(str string) string { 71 if strings.Contains(str, ".") { 72 newStrs := []string{} 73 for _, str := range strings.Split(str, ".") { 74 newStrs = append(newStrs, scope.Dialect().Quote(str)) 75 } 76 return strings.Join(newStrs, ".") 77 } 78 79 return scope.Dialect().Quote(str) 80} 81 82// Err add error to Scope 83func (scope *Scope) Err(err error) error { 84 if err != nil { 85 scope.db.AddError(err) 86 } 87 return err 88} 89 90// HasError check if there are any error 91func (scope *Scope) HasError() bool { 92 return scope.db.Error != nil 93} 94 95// Log print log message 96func (scope *Scope) Log(v ...interface{}) { 97 scope.db.log(v...) 98} 99 100// SkipLeft skip remaining callbacks 101func (scope *Scope) SkipLeft() { 102 scope.skipLeft = true 103} 104 105// Fields get value's fields 106func (scope *Scope) Fields() []*Field { 107 if scope.fields == nil { 108 var ( 109 fields []*Field 110 indirectScopeValue = scope.IndirectValue() 111 isStruct = indirectScopeValue.Kind() == reflect.Struct 112 ) 113 114 for _, structField := range scope.GetModelStruct().StructFields { 115 if isStruct { 116 fieldValue := indirectScopeValue 117 for _, name := range structField.Names { 118 if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() { 119 fieldValue.Set(reflect.New(fieldValue.Type().Elem())) 120 } 121 fieldValue = reflect.Indirect(fieldValue).FieldByName(name) 122 } 123 fields = append(fields, &Field{StructField: structField, Field: fieldValue, IsBlank: isBlank(fieldValue)}) 124 } else { 125 fields = append(fields, &Field{StructField: structField, IsBlank: true}) 126 } 127 } 128 scope.fields = &fields 129 } 130 131 return *scope.fields 132} 133 134// FieldByName find `gorm.Field` with field name or db name 135func (scope *Scope) FieldByName(name string) (field *Field, ok bool) { 136 var ( 137 dbName = ToColumnName(name) 138 mostMatchedField *Field 139 ) 140 141 for _, field := range scope.Fields() { 142 if field.Name == name || field.DBName == name { 143 return field, true 144 } 145 if field.DBName == dbName { 146 mostMatchedField = field 147 } 148 } 149 return mostMatchedField, mostMatchedField != nil 150} 151 152// PrimaryFields return scope's primary fields 153func (scope *Scope) PrimaryFields() (fields []*Field) { 154 for _, field := range scope.Fields() { 155 if field.IsPrimaryKey { 156 fields = append(fields, field) 157 } 158 } 159 return fields 160} 161 162// 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 163func (scope *Scope) PrimaryField() *Field { 164 if primaryFields := scope.GetModelStruct().PrimaryFields; len(primaryFields) > 0 { 165 if len(primaryFields) > 1 { 166 if field, ok := scope.FieldByName("id"); ok { 167 return field 168 } 169 } 170 return scope.PrimaryFields()[0] 171 } 172 return nil 173} 174 175// PrimaryKey get main primary field's db name 176func (scope *Scope) PrimaryKey() string { 177 if field := scope.PrimaryField(); field != nil { 178 return field.DBName 179 } 180 return "" 181} 182 183// PrimaryKeyZero check main primary field's value is blank or not 184func (scope *Scope) PrimaryKeyZero() bool { 185 field := scope.PrimaryField() 186 return field == nil || field.IsBlank 187} 188 189// PrimaryKeyValue get the primary key's value 190func (scope *Scope) PrimaryKeyValue() interface{} { 191 if field := scope.PrimaryField(); field != nil && field.Field.IsValid() { 192 return field.Field.Interface() 193 } 194 return 0 195} 196 197// HasColumn to check if has column 198func (scope *Scope) HasColumn(column string) bool { 199 for _, field := range scope.GetStructFields() { 200 if field.IsNormal && (field.Name == column || field.DBName == column) { 201 return true 202 } 203 } 204 return false 205} 206 207// SetColumn to set the column's value, column could be field or field's name/dbname 208func (scope *Scope) SetColumn(column interface{}, value interface{}) error { 209 var updateAttrs = map[string]interface{}{} 210 if attrs, ok := scope.InstanceGet("gorm:update_attrs"); ok { 211 updateAttrs = attrs.(map[string]interface{}) 212 defer scope.InstanceSet("gorm:update_attrs", updateAttrs) 213 } 214 215 if field, ok := column.(*Field); ok { 216 updateAttrs[field.DBName] = value 217 return field.Set(value) 218 } else if name, ok := column.(string); ok { 219 var ( 220 dbName = ToDBName(name) 221 mostMatchedField *Field 222 ) 223 for _, field := range scope.Fields() { 224 if field.DBName == value { 225 updateAttrs[field.DBName] = value 226 return field.Set(value) 227 } 228 if !field.IsIgnored && ((field.DBName == dbName) || (field.Name == name && mostMatchedField == nil)) { 229 mostMatchedField = field 230 } 231 } 232 233 if mostMatchedField != nil { 234 updateAttrs[mostMatchedField.DBName] = value 235 return mostMatchedField.Set(value) 236 } 237 } 238 return errors.New("could not convert column to field") 239} 240 241// CallMethod call scope value's method, if it is a slice, will call its element's method one by one 242func (scope *Scope) CallMethod(methodName string) { 243 if scope.Value == nil { 244 return 245 } 246 247 if indirectScopeValue := scope.IndirectValue(); indirectScopeValue.Kind() == reflect.Slice { 248 for i := 0; i < indirectScopeValue.Len(); i++ { 249 scope.callMethod(methodName, indirectScopeValue.Index(i)) 250 } 251 } else { 252 scope.callMethod(methodName, indirectScopeValue) 253 } 254} 255 256// AddToVars add value as sql's vars, used to prevent SQL injection 257func (scope *Scope) AddToVars(value interface{}) string { 258 _, skipBindVar := scope.InstanceGet("skip_bindvar") 259 260 if expr, ok := value.(*SqlExpr); ok { 261 exp := expr.expr 262 for _, arg := range expr.args { 263 if skipBindVar { 264 scope.AddToVars(arg) 265 } else { 266 exp = strings.Replace(exp, "?", scope.AddToVars(arg), 1) 267 } 268 } 269 return exp 270 } 271 272 scope.SQLVars = append(scope.SQLVars, value) 273 274 if skipBindVar { 275 return "?" 276 } 277 return scope.Dialect().BindVar(len(scope.SQLVars)) 278} 279 280// SelectAttrs return selected attributes 281func (scope *Scope) SelectAttrs() []string { 282 if scope.selectAttrs == nil { 283 attrs := []string{} 284 for _, value := range scope.Search.selects { 285 if str, ok := value.(string); ok { 286 attrs = append(attrs, str) 287 } else if strs, ok := value.([]string); ok { 288 attrs = append(attrs, strs...) 289 } else if strs, ok := value.([]interface{}); ok { 290 for _, str := range strs { 291 attrs = append(attrs, fmt.Sprintf("%v", str)) 292 } 293 } 294 } 295 scope.selectAttrs = &attrs 296 } 297 return *scope.selectAttrs 298} 299 300// OmitAttrs return omitted attributes 301func (scope *Scope) OmitAttrs() []string { 302 return scope.Search.omits 303} 304 305type tabler interface { 306 TableName() string 307} 308 309type dbTabler interface { 310 TableName(*DB) string 311} 312 313// TableName return table name 314func (scope *Scope) TableName() string { 315 if scope.Search != nil && len(scope.Search.tableName) > 0 { 316 return scope.Search.tableName 317 } 318 319 if tabler, ok := scope.Value.(tabler); ok { 320 return tabler.TableName() 321 } 322 323 if tabler, ok := scope.Value.(dbTabler); ok { 324 return tabler.TableName(scope.db) 325 } 326 327 return scope.GetModelStruct().TableName(scope.db.Model(scope.Value)) 328} 329 330// QuotedTableName return quoted table name 331func (scope *Scope) QuotedTableName() (name string) { 332 if scope.Search != nil && len(scope.Search.tableName) > 0 { 333 if strings.Contains(scope.Search.tableName, " ") { 334 return scope.Search.tableName 335 } 336 return scope.Quote(scope.Search.tableName) 337 } 338 339 return scope.Quote(scope.TableName()) 340} 341 342// CombinedConditionSql return combined condition sql 343func (scope *Scope) CombinedConditionSql() string { 344 joinSQL := scope.joinsSQL() 345 whereSQL := scope.whereSQL() 346 if scope.Search.raw { 347 whereSQL = strings.TrimSuffix(strings.TrimPrefix(whereSQL, "WHERE ("), ")") 348 } 349 return joinSQL + whereSQL + scope.groupSQL() + 350 scope.havingSQL() + scope.orderSQL() + scope.limitAndOffsetSQL() 351} 352 353// Raw set raw sql 354func (scope *Scope) Raw(sql string) *Scope { 355 scope.SQL = strings.Replace(sql, "$$$", "?", -1) 356 return scope 357} 358 359// Exec perform generated SQL 360func (scope *Scope) Exec() *Scope { 361 defer scope.trace(NowFunc()) 362 363 if !scope.HasError() { 364 if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil { 365 if count, err := result.RowsAffected(); scope.Err(err) == nil { 366 scope.db.RowsAffected = count 367 } 368 } 369 } 370 return scope 371} 372 373// Set set value by name 374func (scope *Scope) Set(name string, value interface{}) *Scope { 375 scope.db.InstantSet(name, value) 376 return scope 377} 378 379// Get get setting by name 380func (scope *Scope) Get(name string) (interface{}, bool) { 381 return scope.db.Get(name) 382} 383 384// InstanceID get InstanceID for scope 385func (scope *Scope) InstanceID() string { 386 if scope.instanceID == "" { 387 scope.instanceID = fmt.Sprintf("%v%v", &scope, &scope.db) 388 } 389 return scope.instanceID 390} 391 392// InstanceSet set instance setting for current operation, but not for operations in callbacks, like saving associations callback 393func (scope *Scope) InstanceSet(name string, value interface{}) *Scope { 394 return scope.Set(name+scope.InstanceID(), value) 395} 396 397// InstanceGet get instance setting from current operation 398func (scope *Scope) InstanceGet(name string) (interface{}, bool) { 399 return scope.Get(name + scope.InstanceID()) 400} 401 402// Begin start a transaction 403func (scope *Scope) Begin() *Scope { 404 if db, ok := scope.SQLDB().(sqlDb); ok { 405 if tx, err := db.Begin(); scope.Err(err) == nil { 406 scope.db.db = interface{}(tx).(SQLCommon) 407 scope.InstanceSet("gorm:started_transaction", true) 408 } 409 } 410 return scope 411} 412 413// CommitOrRollback commit current transaction if no error happened, otherwise will rollback it 414func (scope *Scope) CommitOrRollback() *Scope { 415 if _, ok := scope.InstanceGet("gorm:started_transaction"); ok { 416 if db, ok := scope.db.db.(sqlTx); ok { 417 if scope.HasError() { 418 db.Rollback() 419 } else { 420 scope.Err(db.Commit()) 421 } 422 scope.db.db = scope.db.parent.db 423 } 424 } 425 return scope 426} 427 428//////////////////////////////////////////////////////////////////////////////// 429// Private Methods For *gorm.Scope 430//////////////////////////////////////////////////////////////////////////////// 431 432func (scope *Scope) callMethod(methodName string, reflectValue reflect.Value) { 433 // Only get address from non-pointer 434 if reflectValue.CanAddr() && reflectValue.Kind() != reflect.Ptr { 435 reflectValue = reflectValue.Addr() 436 } 437 438 if methodValue := reflectValue.MethodByName(methodName); methodValue.IsValid() { 439 switch method := methodValue.Interface().(type) { 440 case func(): 441 method() 442 case func(*Scope): 443 method(scope) 444 case func(*DB): 445 newDB := scope.NewDB() 446 method(newDB) 447 scope.Err(newDB.Error) 448 case func() error: 449 scope.Err(method()) 450 case func(*Scope) error: 451 scope.Err(method(scope)) 452 case func(*DB) error: 453 newDB := scope.NewDB() 454 scope.Err(method(newDB)) 455 scope.Err(newDB.Error) 456 default: 457 scope.Err(fmt.Errorf("unsupported function %v", methodName)) 458 } 459 } 460} 461 462var ( 463 columnRegexp = regexp.MustCompile("^[a-zA-Z\\d]+(\\.[a-zA-Z\\d]+)*$") // only match string like `name`, `users.name` 464 isNumberRegexp = regexp.MustCompile("^\\s*\\d+\\s*$") // match if string is number 465 comparisonRegexp = regexp.MustCompile("(?i) (=|<>|(>|<)(=?)|LIKE|IS|IN) ") 466 countingQueryRegexp = regexp.MustCompile("(?i)^count(.+)$") 467) 468 469func (scope *Scope) quoteIfPossible(str string) string { 470 if columnRegexp.MatchString(str) { 471 return scope.Quote(str) 472 } 473 return str 474} 475 476func (scope *Scope) scan(rows *sql.Rows, columns []string, fields []*Field) { 477 var ( 478 ignored interface{} 479 values = make([]interface{}, len(columns)) 480 selectFields []*Field 481 selectedColumnsMap = map[string]int{} 482 resetFields = map[int]*Field{} 483 ) 484 485 for index, column := range columns { 486 values[index] = &ignored 487 488 selectFields = fields 489 offset := 0 490 if idx, ok := selectedColumnsMap[column]; ok { 491 offset = idx + 1 492 selectFields = selectFields[offset:] 493 } 494 495 for fieldIndex, field := range selectFields { 496 if field.DBName == column { 497 if field.Field.Kind() == reflect.Ptr { 498 values[index] = field.Field.Addr().Interface() 499 } else { 500 reflectValue := reflect.New(reflect.PtrTo(field.Struct.Type)) 501 reflectValue.Elem().Set(field.Field.Addr()) 502 values[index] = reflectValue.Interface() 503 resetFields[index] = field 504 } 505 506 selectedColumnsMap[column] = offset + fieldIndex 507 508 if field.IsNormal { 509 break 510 } 511 } 512 } 513 } 514 515 scope.Err(rows.Scan(values...)) 516 517 for index, field := range resetFields { 518 if v := reflect.ValueOf(values[index]).Elem().Elem(); v.IsValid() { 519 field.Field.Set(v) 520 } 521 } 522} 523 524func (scope *Scope) primaryCondition(value interface{}) string { 525 return fmt.Sprintf("(%v.%v = %v)", scope.QuotedTableName(), scope.Quote(scope.PrimaryKey()), value) 526} 527 528func (scope *Scope) buildCondition(clause map[string]interface{}, include bool) (str string) { 529 var ( 530 quotedTableName = scope.QuotedTableName() 531 quotedPrimaryKey = scope.Quote(scope.PrimaryKey()) 532 equalSQL = "=" 533 inSQL = "IN" 534 ) 535 536 // If building not conditions 537 if !include { 538 equalSQL = "<>" 539 inSQL = "NOT IN" 540 } 541 542 switch value := clause["query"].(type) { 543 case sql.NullInt64: 544 return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, value.Int64) 545 case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: 546 return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, value) 547 case []int, []int8, []int16, []int32, []int64, []uint, []uint8, []uint16, []uint32, []uint64, []string, []interface{}: 548 if !include && reflect.ValueOf(value).Len() == 0 { 549 return 550 } 551 str = fmt.Sprintf("(%v.%v %s (?))", quotedTableName, quotedPrimaryKey, inSQL) 552 clause["args"] = []interface{}{value} 553 case string: 554 if isNumberRegexp.MatchString(value) { 555 return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, scope.AddToVars(value)) 556 } 557 558 if value != "" { 559 if !include { 560 if comparisonRegexp.MatchString(value) { 561 str = fmt.Sprintf("NOT (%v)", value) 562 } else { 563 str = fmt.Sprintf("(%v.%v NOT IN (?))", quotedTableName, scope.Quote(value)) 564 } 565 } else { 566 str = fmt.Sprintf("(%v)", value) 567 } 568 } 569 case map[string]interface{}: 570 var sqls []string 571 for key, value := range value { 572 if value != nil { 573 sqls = append(sqls, fmt.Sprintf("(%v.%v %s %v)", quotedTableName, scope.Quote(key), equalSQL, scope.AddToVars(value))) 574 } else { 575 if !include { 576 sqls = append(sqls, fmt.Sprintf("(%v.%v IS NOT NULL)", quotedTableName, scope.Quote(key))) 577 } else { 578 sqls = append(sqls, fmt.Sprintf("(%v.%v IS NULL)", quotedTableName, scope.Quote(key))) 579 } 580 } 581 } 582 return strings.Join(sqls, " AND ") 583 case interface{}: 584 var sqls []string 585 newScope := scope.New(value) 586 587 if len(newScope.Fields()) == 0 { 588 scope.Err(fmt.Errorf("invalid query condition: %v", value)) 589 return 590 } 591 scopeQuotedTableName := newScope.QuotedTableName() 592 for _, field := range newScope.Fields() { 593 if !field.IsIgnored && !field.IsBlank && field.Relationship == nil { 594 sqls = append(sqls, fmt.Sprintf("(%v.%v %s %v)", scopeQuotedTableName, scope.Quote(field.DBName), equalSQL, scope.AddToVars(field.Field.Interface()))) 595 } 596 } 597 return strings.Join(sqls, " AND ") 598 default: 599 scope.Err(fmt.Errorf("invalid query condition: %v", value)) 600 return 601 } 602 603 replacements := []string{} 604 args := clause["args"].([]interface{}) 605 for _, arg := range args { 606 var err error 607 switch reflect.ValueOf(arg).Kind() { 608 case reflect.Slice: // For where("id in (?)", []int64{1,2}) 609 if scanner, ok := interface{}(arg).(driver.Valuer); ok { 610 arg, err = scanner.Value() 611 replacements = append(replacements, scope.AddToVars(arg)) 612 } else if b, ok := arg.([]byte); ok { 613 replacements = append(replacements, scope.AddToVars(b)) 614 } else if as, ok := arg.([][]interface{}); ok { 615 var tempMarks []string 616 for _, a := range as { 617 var arrayMarks []string 618 for _, v := range a { 619 arrayMarks = append(arrayMarks, scope.AddToVars(v)) 620 } 621 622 if len(arrayMarks) > 0 { 623 tempMarks = append(tempMarks, fmt.Sprintf("(%v)", strings.Join(arrayMarks, ","))) 624 } 625 } 626 627 if len(tempMarks) > 0 { 628 replacements = append(replacements, strings.Join(tempMarks, ",")) 629 } 630 } else if values := reflect.ValueOf(arg); values.Len() > 0 { 631 var tempMarks []string 632 for i := 0; i < values.Len(); i++ { 633 tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface())) 634 } 635 replacements = append(replacements, strings.Join(tempMarks, ",")) 636 } else { 637 replacements = append(replacements, scope.AddToVars(Expr("NULL"))) 638 } 639 default: 640 if valuer, ok := interface{}(arg).(driver.Valuer); ok { 641 arg, err = valuer.Value() 642 } 643 644 replacements = append(replacements, scope.AddToVars(arg)) 645 } 646 647 if err != nil { 648 scope.Err(err) 649 } 650 } 651 652 buff := bytes.NewBuffer([]byte{}) 653 i := 0 654 for _, s := range str { 655 if s == '?' && len(replacements) > i { 656 buff.WriteString(replacements[i]) 657 i++ 658 } else { 659 buff.WriteRune(s) 660 } 661 } 662 663 str = buff.String() 664 665 return 666} 667 668func (scope *Scope) buildSelectQuery(clause map[string]interface{}) (str string) { 669 switch value := clause["query"].(type) { 670 case string: 671 str = value 672 case []string: 673 str = strings.Join(value, ", ") 674 } 675 676 args := clause["args"].([]interface{}) 677 replacements := []string{} 678 for _, arg := range args { 679 switch reflect.ValueOf(arg).Kind() { 680 case reflect.Slice: 681 values := reflect.ValueOf(arg) 682 var tempMarks []string 683 for i := 0; i < values.Len(); i++ { 684 tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface())) 685 } 686 replacements = append(replacements, strings.Join(tempMarks, ",")) 687 default: 688 if valuer, ok := interface{}(arg).(driver.Valuer); ok { 689 arg, _ = valuer.Value() 690 } 691 replacements = append(replacements, scope.AddToVars(arg)) 692 } 693 } 694 695 buff := bytes.NewBuffer([]byte{}) 696 i := 0 697 for pos, char := range str { 698 if str[pos] == '?' { 699 buff.WriteString(replacements[i]) 700 i++ 701 } else { 702 buff.WriteRune(char) 703 } 704 } 705 706 str = buff.String() 707 708 return 709} 710 711func (scope *Scope) whereSQL() (sql string) { 712 var ( 713 quotedTableName = scope.QuotedTableName() 714 deletedAtField, hasDeletedAtField = scope.FieldByName("DeletedAt") 715 primaryConditions, andConditions, orConditions []string 716 ) 717 718 if !scope.Search.Unscoped && hasDeletedAtField { 719 sql := fmt.Sprintf("%v.%v IS NULL", quotedTableName, scope.Quote(deletedAtField.DBName)) 720 primaryConditions = append(primaryConditions, sql) 721 } 722 723 if !scope.PrimaryKeyZero() { 724 for _, field := range scope.PrimaryFields() { 725 sql := fmt.Sprintf("%v.%v = %v", quotedTableName, scope.Quote(field.DBName), scope.AddToVars(field.Field.Interface())) 726 primaryConditions = append(primaryConditions, sql) 727 } 728 } 729 730 for _, clause := range scope.Search.whereConditions { 731 if sql := scope.buildCondition(clause, true); sql != "" { 732 andConditions = append(andConditions, sql) 733 } 734 } 735 736 for _, clause := range scope.Search.orConditions { 737 if sql := scope.buildCondition(clause, true); sql != "" { 738 orConditions = append(orConditions, sql) 739 } 740 } 741 742 for _, clause := range scope.Search.notConditions { 743 if sql := scope.buildCondition(clause, false); sql != "" { 744 andConditions = append(andConditions, sql) 745 } 746 } 747 748 orSQL := strings.Join(orConditions, " OR ") 749 combinedSQL := strings.Join(andConditions, " AND ") 750 if len(combinedSQL) > 0 { 751 if len(orSQL) > 0 { 752 combinedSQL = combinedSQL + " OR " + orSQL 753 } 754 } else { 755 combinedSQL = orSQL 756 } 757 758 if len(primaryConditions) > 0 { 759 sql = "WHERE " + strings.Join(primaryConditions, " AND ") 760 if len(combinedSQL) > 0 { 761 sql = sql + " AND (" + combinedSQL + ")" 762 } 763 } else if len(combinedSQL) > 0 { 764 sql = "WHERE " + combinedSQL 765 } 766 return 767} 768 769func (scope *Scope) selectSQL() string { 770 if len(scope.Search.selects) == 0 { 771 if len(scope.Search.joinConditions) > 0 { 772 return fmt.Sprintf("%v.*", scope.QuotedTableName()) 773 } 774 return "*" 775 } 776 return scope.buildSelectQuery(scope.Search.selects) 777} 778 779func (scope *Scope) orderSQL() string { 780 if len(scope.Search.orders) == 0 || scope.Search.ignoreOrderQuery { 781 return "" 782 } 783 784 var orders []string 785 for _, order := range scope.Search.orders { 786 if str, ok := order.(string); ok { 787 orders = append(orders, scope.quoteIfPossible(str)) 788 } else if expr, ok := order.(*SqlExpr); ok { 789 exp := expr.expr 790 for _, arg := range expr.args { 791 exp = strings.Replace(exp, "?", scope.AddToVars(arg), 1) 792 } 793 orders = append(orders, exp) 794 } 795 } 796 return " ORDER BY " + strings.Join(orders, ",") 797} 798 799func (scope *Scope) limitAndOffsetSQL() string { 800 sql, err := scope.Dialect().LimitAndOffsetSQL(scope.Search.limit, scope.Search.offset) 801 scope.Err(err) 802 return sql 803} 804 805func (scope *Scope) groupSQL() string { 806 if len(scope.Search.group) == 0 { 807 return "" 808 } 809 return " GROUP BY " + scope.Search.group 810} 811 812func (scope *Scope) havingSQL() string { 813 if len(scope.Search.havingConditions) == 0 { 814 return "" 815 } 816 817 var andConditions []string 818 for _, clause := range scope.Search.havingConditions { 819 if sql := scope.buildCondition(clause, true); sql != "" { 820 andConditions = append(andConditions, sql) 821 } 822 } 823 824 combinedSQL := strings.Join(andConditions, " AND ") 825 if len(combinedSQL) == 0 { 826 return "" 827 } 828 829 return " HAVING " + combinedSQL 830} 831 832func (scope *Scope) joinsSQL() string { 833 var joinConditions []string 834 for _, clause := range scope.Search.joinConditions { 835 if sql := scope.buildCondition(clause, true); sql != "" { 836 joinConditions = append(joinConditions, strings.TrimSuffix(strings.TrimPrefix(sql, "("), ")")) 837 } 838 } 839 840 return strings.Join(joinConditions, " ") + " " 841} 842 843func (scope *Scope) prepareQuerySQL() { 844 if scope.Search.raw { 845 scope.Raw(scope.CombinedConditionSql()) 846 } else { 847 scope.Raw(fmt.Sprintf("SELECT %v FROM %v %v", scope.selectSQL(), scope.QuotedTableName(), scope.CombinedConditionSql())) 848 } 849 return 850} 851 852func (scope *Scope) inlineCondition(values ...interface{}) *Scope { 853 if len(values) > 0 { 854 scope.Search.Where(values[0], values[1:]...) 855 } 856 return scope 857} 858 859func (scope *Scope) callCallbacks(funcs []*func(s *Scope)) *Scope { 860 defer func() { 861 if err := recover(); err != nil { 862 if db, ok := scope.db.db.(sqlTx); ok { 863 db.Rollback() 864 } 865 panic(err) 866 } 867 }() 868 for _, f := range funcs { 869 (*f)(scope) 870 if scope.skipLeft { 871 break 872 } 873 } 874 return scope 875} 876 877func convertInterfaceToMap(values interface{}, withIgnoredField bool, db *DB) map[string]interface{} { 878 var attrs = map[string]interface{}{} 879 880 switch value := values.(type) { 881 case map[string]interface{}: 882 return value 883 case []interface{}: 884 for _, v := range value { 885 for key, value := range convertInterfaceToMap(v, withIgnoredField, db) { 886 attrs[key] = value 887 } 888 } 889 case interface{}: 890 reflectValue := reflect.ValueOf(values) 891 892 switch reflectValue.Kind() { 893 case reflect.Map: 894 for _, key := range reflectValue.MapKeys() { 895 attrs[ToColumnName(key.Interface().(string))] = reflectValue.MapIndex(key).Interface() 896 } 897 default: 898 for _, field := range (&Scope{Value: values, db: db}).Fields() { 899 if !field.IsBlank && (withIgnoredField || !field.IsIgnored) { 900 attrs[field.DBName] = field.Field.Interface() 901 } 902 } 903 } 904 } 905 return attrs 906} 907 908func (scope *Scope) updatedAttrsWithValues(value interface{}) (results map[string]interface{}, hasUpdate bool) { 909 if scope.IndirectValue().Kind() != reflect.Struct { 910 return convertInterfaceToMap(value, false, scope.db), true 911 } 912 913 results = map[string]interface{}{} 914 915 for key, value := range convertInterfaceToMap(value, true, scope.db) { 916 if field, ok := scope.FieldByName(key); ok { 917 if scope.changeableField(field) { 918 if _, ok := value.(*SqlExpr); ok { 919 hasUpdate = true 920 results[field.DBName] = value 921 } else { 922 err := field.Set(value) 923 if field.IsNormal && !field.IsIgnored { 924 hasUpdate = true 925 if err == ErrUnaddressable { 926 results[field.DBName] = value 927 } else { 928 results[field.DBName] = field.Field.Interface() 929 } 930 } 931 } 932 } 933 } else { 934 results[key] = value 935 } 936 } 937 return 938} 939 940func (scope *Scope) row() *sql.Row { 941 defer scope.trace(NowFunc()) 942 943 result := &RowQueryResult{} 944 scope.InstanceSet("row_query_result", result) 945 scope.callCallbacks(scope.db.parent.callbacks.rowQueries) 946 947 return result.Row 948} 949 950func (scope *Scope) rows() (*sql.Rows, error) { 951 defer scope.trace(NowFunc()) 952 953 result := &RowsQueryResult{} 954 scope.InstanceSet("row_query_result", result) 955 scope.callCallbacks(scope.db.parent.callbacks.rowQueries) 956 957 return result.Rows, result.Error 958} 959 960func (scope *Scope) initialize() *Scope { 961 for _, clause := range scope.Search.whereConditions { 962 scope.updatedAttrsWithValues(clause["query"]) 963 } 964 scope.updatedAttrsWithValues(scope.Search.initAttrs) 965 scope.updatedAttrsWithValues(scope.Search.assignAttrs) 966 return scope 967} 968 969func (scope *Scope) isQueryForColumn(query interface{}, column string) bool { 970 queryStr := strings.ToLower(fmt.Sprint(query)) 971 if queryStr == column { 972 return true 973 } 974 975 if strings.HasSuffix(queryStr, "as "+column) { 976 return true 977 } 978 979 if strings.HasSuffix(queryStr, "as "+scope.Quote(column)) { 980 return true 981 } 982 983 return false 984} 985 986func (scope *Scope) pluck(column string, value interface{}) *Scope { 987 dest := reflect.Indirect(reflect.ValueOf(value)) 988 if dest.Kind() != reflect.Slice { 989 scope.Err(fmt.Errorf("results should be a slice, not %s", dest.Kind())) 990 return scope 991 } 992 993 if dest.Len() > 0 { 994 dest.Set(reflect.Zero(dest.Type())) 995 } 996 997 if query, ok := scope.Search.selects["query"]; !ok || !scope.isQueryForColumn(query, column) { 998 scope.Search.Select(column) 999 } 1000 1001 rows, err := scope.rows() 1002 if scope.Err(err) == nil { 1003 defer rows.Close() 1004 for rows.Next() { 1005 elem := reflect.New(dest.Type().Elem()).Interface() 1006 scope.Err(rows.Scan(elem)) 1007 dest.Set(reflect.Append(dest, reflect.ValueOf(elem).Elem())) 1008 } 1009 1010 if err := rows.Err(); err != nil { 1011 scope.Err(err) 1012 } 1013 } 1014 return scope 1015} 1016 1017func (scope *Scope) count(value interface{}) *Scope { 1018 if query, ok := scope.Search.selects["query"]; !ok || !countingQueryRegexp.MatchString(fmt.Sprint(query)) { 1019 if len(scope.Search.group) != 0 { 1020 if len(scope.Search.havingConditions) != 0 { 1021 scope.prepareQuerySQL() 1022 scope.Search = &search{} 1023 scope.Search.Select("count(*)") 1024 scope.Search.Table(fmt.Sprintf("( %s ) AS count_table", scope.SQL)) 1025 } else { 1026 scope.Search.Select("count(*) FROM ( SELECT count(*) as name ") 1027 scope.Search.group += " ) AS count_table" 1028 } 1029 } else { 1030 scope.Search.Select("count(*)") 1031 } 1032 } 1033 scope.Search.ignoreOrderQuery = true 1034 scope.Err(scope.row().Scan(value)) 1035 return scope 1036} 1037 1038func (scope *Scope) typeName() string { 1039 typ := scope.IndirectValue().Type() 1040 1041 for typ.Kind() == reflect.Slice || typ.Kind() == reflect.Ptr { 1042 typ = typ.Elem() 1043 } 1044 1045 return typ.Name() 1046} 1047 1048// trace print sql log 1049func (scope *Scope) trace(t time.Time) { 1050 if len(scope.SQL) > 0 { 1051 scope.db.slog(scope.SQL, t, scope.SQLVars...) 1052 } 1053} 1054 1055func (scope *Scope) changeableField(field *Field) bool { 1056 if selectAttrs := scope.SelectAttrs(); len(selectAttrs) > 0 { 1057 for _, attr := range selectAttrs { 1058 if field.Name == attr || field.DBName == attr { 1059 return true 1060 } 1061 } 1062 return false 1063 } 1064 1065 for _, attr := range scope.OmitAttrs() { 1066 if field.Name == attr || field.DBName == attr { 1067 return false 1068 } 1069 } 1070 1071 return true 1072} 1073 1074func (scope *Scope) related(value interface{}, foreignKeys ...string) *Scope { 1075 toScope := scope.db.NewScope(value) 1076 tx := scope.db.Set("gorm:association:source", scope.Value) 1077 1078 for _, foreignKey := range append(foreignKeys, toScope.typeName()+"Id", scope.typeName()+"Id") { 1079 fromField, _ := scope.FieldByName(foreignKey) 1080 toField, _ := toScope.FieldByName(foreignKey) 1081 1082 if fromField != nil { 1083 if relationship := fromField.Relationship; relationship != nil { 1084 if relationship.Kind == "many_to_many" { 1085 joinTableHandler := relationship.JoinTableHandler 1086 scope.Err(joinTableHandler.JoinWith(joinTableHandler, tx, scope.Value).Find(value).Error) 1087 } else if relationship.Kind == "belongs_to" { 1088 for idx, foreignKey := range relationship.ForeignDBNames { 1089 if field, ok := scope.FieldByName(foreignKey); ok { 1090 tx = tx.Where(fmt.Sprintf("%v = ?", scope.Quote(relationship.AssociationForeignDBNames[idx])), field.Field.Interface()) 1091 } 1092 } 1093 scope.Err(tx.Find(value).Error) 1094 } else if relationship.Kind == "has_many" || relationship.Kind == "has_one" { 1095 for idx, foreignKey := range relationship.ForeignDBNames { 1096 if field, ok := scope.FieldByName(relationship.AssociationForeignDBNames[idx]); ok { 1097 tx = tx.Where(fmt.Sprintf("%v = ?", scope.Quote(foreignKey)), field.Field.Interface()) 1098 } 1099 } 1100 1101 if relationship.PolymorphicType != "" { 1102 tx = tx.Where(fmt.Sprintf("%v = ?", scope.Quote(relationship.PolymorphicDBName)), relationship.PolymorphicValue) 1103 } 1104 scope.Err(tx.Find(value).Error) 1105 } 1106 } else { 1107 sql := fmt.Sprintf("%v = ?", scope.Quote(toScope.PrimaryKey())) 1108 scope.Err(tx.Where(sql, fromField.Field.Interface()).Find(value).Error) 1109 } 1110 return scope 1111 } else if toField != nil { 1112 sql := fmt.Sprintf("%v = ?", scope.Quote(toField.DBName)) 1113 scope.Err(tx.Where(sql, scope.PrimaryKeyValue()).Find(value).Error) 1114 return scope 1115 } 1116 } 1117 1118 scope.Err(fmt.Errorf("invalid association %v", foreignKeys)) 1119 return scope 1120} 1121 1122// getTableOptions return the table options string or an empty string if the table options does not exist 1123func (scope *Scope) getTableOptions() string { 1124 tableOptions, ok := scope.Get("gorm:table_options") 1125 if !ok { 1126 return "" 1127 } 1128 return " " + tableOptions.(string) 1129} 1130 1131func (scope *Scope) createJoinTable(field *StructField) { 1132 if relationship := field.Relationship; relationship != nil && relationship.JoinTableHandler != nil { 1133 joinTableHandler := relationship.JoinTableHandler 1134 joinTable := joinTableHandler.Table(scope.db) 1135 if !scope.Dialect().HasTable(joinTable) { 1136 toScope := &Scope{Value: reflect.New(field.Struct.Type).Interface()} 1137 1138 var sqlTypes, primaryKeys []string 1139 for idx, fieldName := range relationship.ForeignFieldNames { 1140 if field, ok := scope.FieldByName(fieldName); ok { 1141 foreignKeyStruct := field.clone() 1142 foreignKeyStruct.IsPrimaryKey = false 1143 foreignKeyStruct.TagSettingsSet("IS_JOINTABLE_FOREIGNKEY", "true") 1144 foreignKeyStruct.TagSettingsDelete("AUTO_INCREMENT") 1145 sqlTypes = append(sqlTypes, scope.Quote(relationship.ForeignDBNames[idx])+" "+scope.Dialect().DataTypeOf(foreignKeyStruct)) 1146 primaryKeys = append(primaryKeys, scope.Quote(relationship.ForeignDBNames[idx])) 1147 } 1148 } 1149 1150 for idx, fieldName := range relationship.AssociationForeignFieldNames { 1151 if field, ok := toScope.FieldByName(fieldName); ok { 1152 foreignKeyStruct := field.clone() 1153 foreignKeyStruct.IsPrimaryKey = false 1154 foreignKeyStruct.TagSettingsSet("IS_JOINTABLE_FOREIGNKEY", "true") 1155 foreignKeyStruct.TagSettingsDelete("AUTO_INCREMENT") 1156 sqlTypes = append(sqlTypes, scope.Quote(relationship.AssociationForeignDBNames[idx])+" "+scope.Dialect().DataTypeOf(foreignKeyStruct)) 1157 primaryKeys = append(primaryKeys, scope.Quote(relationship.AssociationForeignDBNames[idx])) 1158 } 1159 } 1160 1161 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) 1162 } 1163 scope.NewDB().Table(joinTable).AutoMigrate(joinTableHandler) 1164 } 1165} 1166 1167func (scope *Scope) createTable() *Scope { 1168 var tags []string 1169 var primaryKeys []string 1170 var primaryKeyInColumnType = false 1171 for _, field := range scope.GetModelStruct().StructFields { 1172 if field.IsNormal { 1173 sqlTag := scope.Dialect().DataTypeOf(field) 1174 1175 // Check if the primary key constraint was specified as 1176 // part of the column type. If so, we can only support 1177 // one column as the primary key. 1178 if strings.Contains(strings.ToLower(sqlTag), "primary key") { 1179 primaryKeyInColumnType = true 1180 } 1181 1182 tags = append(tags, scope.Quote(field.DBName)+" "+sqlTag) 1183 } 1184 1185 if field.IsPrimaryKey { 1186 primaryKeys = append(primaryKeys, scope.Quote(field.DBName)) 1187 } 1188 scope.createJoinTable(field) 1189 } 1190 1191 var primaryKeyStr string 1192 if len(primaryKeys) > 0 && !primaryKeyInColumnType { 1193 primaryKeyStr = fmt.Sprintf(", PRIMARY KEY (%v)", strings.Join(primaryKeys, ",")) 1194 } 1195 1196 scope.Raw(fmt.Sprintf("CREATE TABLE %v (%v %v)%s", scope.QuotedTableName(), strings.Join(tags, ","), primaryKeyStr, scope.getTableOptions())).Exec() 1197 1198 scope.autoIndex() 1199 return scope 1200} 1201 1202func (scope *Scope) dropTable() *Scope { 1203 scope.Raw(fmt.Sprintf("DROP TABLE %v", scope.QuotedTableName())).Exec() 1204 return scope 1205} 1206 1207func (scope *Scope) modifyColumn(column string, typ string) { 1208 scope.db.AddError(scope.Dialect().ModifyColumn(scope.QuotedTableName(), scope.Quote(column), typ)) 1209} 1210 1211func (scope *Scope) dropColumn(column string) { 1212 scope.Raw(fmt.Sprintf("ALTER TABLE %v DROP COLUMN %v", scope.QuotedTableName(), scope.Quote(column))).Exec() 1213} 1214 1215func (scope *Scope) addIndex(unique bool, indexName string, column ...string) { 1216 if scope.Dialect().HasIndex(scope.TableName(), indexName) { 1217 return 1218 } 1219 1220 var columns []string 1221 for _, name := range column { 1222 columns = append(columns, scope.quoteIfPossible(name)) 1223 } 1224 1225 sqlCreate := "CREATE INDEX" 1226 if unique { 1227 sqlCreate = "CREATE UNIQUE INDEX" 1228 } 1229 1230 scope.Raw(fmt.Sprintf("%s %v ON %v(%v) %v", sqlCreate, indexName, scope.QuotedTableName(), strings.Join(columns, ", "), scope.whereSQL())).Exec() 1231} 1232 1233func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) { 1234 // Compatible with old generated key 1235 keyName := scope.Dialect().BuildKeyName(scope.TableName(), field, dest, "foreign") 1236 1237 if scope.Dialect().HasForeignKey(scope.TableName(), keyName) { 1238 return 1239 } 1240 var query = `ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s ON DELETE %s ON UPDATE %s;` 1241 scope.Raw(fmt.Sprintf(query, scope.QuotedTableName(), scope.quoteIfPossible(keyName), scope.quoteIfPossible(field), dest, onDelete, onUpdate)).Exec() 1242} 1243 1244func (scope *Scope) removeForeignKey(field string, dest string) { 1245 keyName := scope.Dialect().BuildKeyName(scope.TableName(), field, dest, "foreign") 1246 if !scope.Dialect().HasForeignKey(scope.TableName(), keyName) { 1247 return 1248 } 1249 var mysql mysql 1250 var query string 1251 if scope.Dialect().GetName() == mysql.GetName() { 1252 query = `ALTER TABLE %s DROP FOREIGN KEY %s;` 1253 } else { 1254 query = `ALTER TABLE %s DROP CONSTRAINT %s;` 1255 } 1256 1257 scope.Raw(fmt.Sprintf(query, scope.QuotedTableName(), scope.quoteIfPossible(keyName))).Exec() 1258} 1259 1260func (scope *Scope) removeIndex(indexName string) { 1261 scope.Dialect().RemoveIndex(scope.TableName(), indexName) 1262} 1263 1264func (scope *Scope) autoMigrate() *Scope { 1265 tableName := scope.TableName() 1266 quotedTableName := scope.QuotedTableName() 1267 1268 if !scope.Dialect().HasTable(tableName) { 1269 scope.createTable() 1270 } else { 1271 for _, field := range scope.GetModelStruct().StructFields { 1272 if !scope.Dialect().HasColumn(tableName, field.DBName) { 1273 if field.IsNormal { 1274 sqlTag := scope.Dialect().DataTypeOf(field) 1275 scope.Raw(fmt.Sprintf("ALTER TABLE %v ADD %v %v;", quotedTableName, scope.Quote(field.DBName), sqlTag)).Exec() 1276 } 1277 } 1278 scope.createJoinTable(field) 1279 } 1280 scope.autoIndex() 1281 } 1282 return scope 1283} 1284 1285func (scope *Scope) autoIndex() *Scope { 1286 var indexes = map[string][]string{} 1287 var uniqueIndexes = map[string][]string{} 1288 1289 for _, field := range scope.GetStructFields() { 1290 if name, ok := field.TagSettingsGet("INDEX"); ok { 1291 names := strings.Split(name, ",") 1292 1293 for _, name := range names { 1294 if name == "INDEX" || name == "" { 1295 name = scope.Dialect().BuildKeyName("idx", scope.TableName(), field.DBName) 1296 } 1297 name, column := scope.Dialect().NormalizeIndexAndColumn(name, field.DBName) 1298 indexes[name] = append(indexes[name], column) 1299 } 1300 } 1301 1302 if name, ok := field.TagSettingsGet("UNIQUE_INDEX"); ok { 1303 names := strings.Split(name, ",") 1304 1305 for _, name := range names { 1306 if name == "UNIQUE_INDEX" || name == "" { 1307 name = scope.Dialect().BuildKeyName("uix", scope.TableName(), field.DBName) 1308 } 1309 name, column := scope.Dialect().NormalizeIndexAndColumn(name, field.DBName) 1310 uniqueIndexes[name] = append(uniqueIndexes[name], column) 1311 } 1312 } 1313 } 1314 1315 for name, columns := range indexes { 1316 if db := scope.NewDB().Table(scope.TableName()).Model(scope.Value).AddIndex(name, columns...); db.Error != nil { 1317 scope.db.AddError(db.Error) 1318 } 1319 } 1320 1321 for name, columns := range uniqueIndexes { 1322 if db := scope.NewDB().Table(scope.TableName()).Model(scope.Value).AddUniqueIndex(name, columns...); db.Error != nil { 1323 scope.db.AddError(db.Error) 1324 } 1325 } 1326 1327 return scope 1328} 1329 1330func (scope *Scope) getColumnAsArray(columns []string, values ...interface{}) (results [][]interface{}) { 1331 resultMap := make(map[string][]interface{}) 1332 for _, value := range values { 1333 indirectValue := indirect(reflect.ValueOf(value)) 1334 1335 switch indirectValue.Kind() { 1336 case reflect.Slice: 1337 for i := 0; i < indirectValue.Len(); i++ { 1338 var result []interface{} 1339 var object = indirect(indirectValue.Index(i)) 1340 var hasValue = false 1341 for _, column := range columns { 1342 field := object.FieldByName(column) 1343 if hasValue || !isBlank(field) { 1344 hasValue = true 1345 } 1346 result = append(result, field.Interface()) 1347 } 1348 1349 if hasValue { 1350 h := fmt.Sprint(result...) 1351 if _, exist := resultMap[h]; !exist { 1352 resultMap[h] = result 1353 } 1354 } 1355 } 1356 case reflect.Struct: 1357 var result []interface{} 1358 var hasValue = false 1359 for _, column := range columns { 1360 field := indirectValue.FieldByName(column) 1361 if hasValue || !isBlank(field) { 1362 hasValue = true 1363 } 1364 result = append(result, field.Interface()) 1365 } 1366 1367 if hasValue { 1368 h := fmt.Sprint(result...) 1369 if _, exist := resultMap[h]; !exist { 1370 resultMap[h] = result 1371 } 1372 } 1373 } 1374 } 1375 for _, v := range resultMap { 1376 results = append(results, v) 1377 } 1378 return 1379} 1380 1381func (scope *Scope) getColumnAsScope(column string) *Scope { 1382 indirectScopeValue := scope.IndirectValue() 1383 1384 switch indirectScopeValue.Kind() { 1385 case reflect.Slice: 1386 if fieldStruct, ok := scope.GetModelStruct().ModelType.FieldByName(column); ok { 1387 fieldType := fieldStruct.Type 1388 if fieldType.Kind() == reflect.Slice || fieldType.Kind() == reflect.Ptr { 1389 fieldType = fieldType.Elem() 1390 } 1391 1392 resultsMap := map[interface{}]bool{} 1393 results := reflect.New(reflect.SliceOf(reflect.PtrTo(fieldType))).Elem() 1394 1395 for i := 0; i < indirectScopeValue.Len(); i++ { 1396 result := indirect(indirect(indirectScopeValue.Index(i)).FieldByName(column)) 1397 1398 if result.Kind() == reflect.Slice { 1399 for j := 0; j < result.Len(); j++ { 1400 if elem := result.Index(j); elem.CanAddr() && resultsMap[elem.Addr()] != true { 1401 resultsMap[elem.Addr()] = true 1402 results = reflect.Append(results, elem.Addr()) 1403 } 1404 } 1405 } else if result.CanAddr() && resultsMap[result.Addr()] != true { 1406 resultsMap[result.Addr()] = true 1407 results = reflect.Append(results, result.Addr()) 1408 } 1409 } 1410 return scope.New(results.Interface()) 1411 } 1412 case reflect.Struct: 1413 if field := indirectScopeValue.FieldByName(column); field.CanAddr() { 1414 return scope.New(field.Addr().Interface()) 1415 } 1416 } 1417 return nil 1418} 1419 1420func (scope *Scope) hasConditions() bool { 1421 return !scope.PrimaryKeyZero() || 1422 len(scope.Search.whereConditions) > 0 || 1423 len(scope.Search.orConditions) > 0 || 1424 len(scope.Search.notConditions) > 0 1425} 1426