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