diff --git a/README.md b/README.md index c7536421..f25e8e81 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,8 @@ db.Where("name in (?)", []string["jinzhu", "jinzhu 2"]).Find(&users) //// users -> select * from users name in ('jinzhu', 'jinzhu 2'); db.Where("name LIKE ?", "%jin%").Find(&users) //// users -> select * from users name LIKE "%jinzhu%"; +db.Where(&User{Name: "jinzhu", Age: 20}).First(&user) +//// user -> select * from users name = "jinzhu" and age = 20 limit 1; db.Where("birthday < ?", time.Now()).Find(&users) // Inline search condition @@ -75,6 +77,8 @@ db.Find(&users, "name = ?", "jinzhu") //// users -> select * from users where name = "jinzhu"; db.Find(&users, "name <> ? and age > ?", "jinzhu", 20) //// users -> select * from users where name <> "jinzhu" and age > 20; +db.Find(&users, &User{Age: 20}) +//// users -> select * from users where age = 20; // Select db.Select("name").Find(&users) @@ -243,7 +247,6 @@ db.Where("mail_type = ?", "TEXT").Find(&users1).Table("deleted_users").First(&us ``` ## TODO -* Query with struct * SubStruct * Index, Unique, Valiations * Auto Migration diff --git a/do.go b/do.go index 796e452f..cd163ae8 100644 --- a/do.go +++ b/do.go @@ -330,9 +330,10 @@ func (s *Do) primaryCondiation(value interface{}) string { } func (s *Do) buildWhereCondition(clause map[string]interface{}) (str string) { - switch clause["query"].(type) { + query := clause["query"] + switch query.(type) { case string: - value := clause["query"].(string) + value := query.(string) if regexp.MustCompile("^\\s*\\d+\\s*$").MatchString(value) { id, _ := strconv.Atoi(value) return s.primaryCondiation(s.addToVars(id)) @@ -340,10 +341,17 @@ func (s *Do) buildWhereCondition(clause map[string]interface{}) (str string) { str = "( " + value + " )" } case int, int64, int32: - return s.primaryCondiation(s.addToVars(clause["query"])) + return s.primaryCondiation(s.addToVars(query)) case []int64, []int, []int32, []string: str = fmt.Sprintf("(%v in (?))", s.model.primaryKeyDb()) - clause["args"] = []interface{}{clause["query"]} + clause["args"] = []interface{}{query} + case interface{}: + m := &Model{data: query, driver: s.driver} + var sqls []string + for _, field := range m.columnsHasValue("") { + sqls = append(sqls, fmt.Sprintf(" ( %v = %v ) ", field.DbName, s.addToVars(field.Value))) + } + return strings.Join(sqls, ",") } args := clause["args"].([]interface{}) diff --git a/gorm_test.go b/gorm_test.go index f7d3f095..e5b0cbf3 100644 --- a/gorm_test.go +++ b/gorm_test.go @@ -51,7 +51,7 @@ func init() { err = db.Exec("drop table users;").Error if err != nil { - fmt.Printf("Got error when try to delete table uses, %+v\n", err) + fmt.Printf("Got error when try to delete table users, %+v\n", err) } db.Exec("drop table products;") @@ -193,9 +193,9 @@ func TestComplexWhere(t *testing.T) { if len(user_ids) != 3 { t.Errorf("Should only found 3 users that age > 20, but have %v", len(users)) } + users = []User{} db.Where(user_ids).Find(&users) - if len(users) != 3 { t.Errorf("Should only found 3 users that age > 20 when search with id map, but have %v", len(users)) } @@ -289,6 +289,35 @@ func TestComplexWhere(t *testing.T) { } } +func TestWhereWithStruct(t *testing.T) { + var user User + db.First(&user, &User{Name: "2"}) + if user.Id == 0 || user.Name != "2" { + t.Errorf("Should be able to search first record with struct") + } + + db.First(&user, User{Name: "2"}) + if user.Id == 0 || user.Name != "2" { + t.Errorf("Should be able to search first record with struct") + } + + db.Where(&User{Name: "2"}).First(&user) + if user.Id == 0 || user.Name != "2" { + t.Errorf("Should be able to search first record with struct") + } + + var users []User + db.Find(&users, &User{Name: "3"}) + if len(users) != 2 { + t.Errorf("Should be able to search all record with struct") + } + + db.Where(User{Name: "3"}).Find(&users) + if user.Id == 0 || user.Name != "2" { + t.Errorf("Should be able to search first record with struct") + } +} + func TestInitlineCondition(t *testing.T) { var u1, u2, u3, u4, u5, u6, u7 User db.Where("name = ?", "3").Order("age desc").First(&u1).First(&u2) diff --git a/model.go b/model.go index 8e786a8c..ac64d319 100644 --- a/model.go +++ b/model.go @@ -22,6 +22,7 @@ type Field struct { AutoCreateTime bool AutoUpdateTime bool IsPrimaryKey bool + IsBlank bool } func (m *Model) primaryKeyZero() bool { @@ -57,7 +58,8 @@ func (m *Model) primaryKeyDb() string { } func (m *Model) fields(operation string) (fields []Field) { - typ := reflect.TypeOf(m.data).Elem() + indirect_value := reflect.Indirect(reflect.ValueOf(m.data)) + typ := indirect_value.Type() for i := 0; i < typ.NumField(); i++ { p := typ.Field(i) @@ -68,7 +70,18 @@ func (m *Model) fields(operation string) (fields []Field) { field.IsPrimaryKey = m.primaryKeyDb() == field.DbName field.AutoCreateTime = "created_at" == field.DbName field.AutoUpdateTime = "updated_at" == field.DbName - value := reflect.ValueOf(m.data).Elem().FieldByName(p.Name) + value := indirect_value.FieldByName(p.Name) + + switch value.Kind() { + case reflect.Int, reflect.Int64, reflect.Int32: + field.IsBlank = value.Int() == 0 + case reflect.String: + field.IsBlank = value.String() == "" + default: + if value, ok := value.Interface().(time.Time); ok { + field.IsBlank = value.IsZero() + } + } switch operation { case "create": @@ -92,6 +105,16 @@ func (m *Model) fields(operation string) (fields []Field) { } } return + +} + +func (m *Model) columnsHasValue(operation string) (fields []Field) { + for _, field := range m.fields(operation) { + if !field.IsBlank { + fields = append(fields, field) + } + } + return } func (m *Model) columnsAndValues(operation string) map[string]interface{} {