forked from mirror/gorm
Make it easy when only change one field with Attr, Assign
This commit is contained in:
parent
0e692a13b1
commit
549c7450ea
|
@ -98,6 +98,8 @@ db.Where(User{Name: "noexisting_user"}).Attrs(User{Age: 20}).FirstOrInit(&user)
|
||||||
//// user -> select * from users where name = 'noexisting_user';
|
//// user -> select * from users where name = 'noexisting_user';
|
||||||
//// If no record found, will assign the attrs to user, so user become:
|
//// If no record found, will assign the attrs to user, so user become:
|
||||||
//// User{Name: "noexisting_user", Age: 20}
|
//// User{Name: "noexisting_user", Age: 20}
|
||||||
|
db.Where(User{Name: "noexisting_user"}).Attrs("age", 20).FirstOrInit(&user)
|
||||||
|
// Same as above
|
||||||
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 20}).FirstOrInit(&user)
|
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 20}).FirstOrInit(&user)
|
||||||
//// user -> select * from users where name = 'jinzhu';
|
//// user -> select * from users where name = 'jinzhu';
|
||||||
//// If found the user, will ingore the attrs:
|
//// If found the user, will ingore the attrs:
|
||||||
|
@ -108,6 +110,8 @@ db.Where(User{Name: "noexisting_user"}).Assign(User{Age: 20}).FirstOrInit(&user)
|
||||||
//// user -> select * from users where name = 'noexisting_user';
|
//// user -> select * from users where name = 'noexisting_user';
|
||||||
//// If no record found, will assign the value to user, so user become:
|
//// If no record found, will assign the value to user, so user become:
|
||||||
//// User{Name: "noexisting_user", Age: 20} (same as FirstOrInit With Attrs)
|
//// User{Name: "noexisting_user", Age: 20} (same as FirstOrInit With Attrs)
|
||||||
|
db.Where(User{Name: "noexisting_user"}).Assign("age", 20).FirstOrInit(&user)
|
||||||
|
// Same as above
|
||||||
//// user -> User{Name: "noexisting_user", Age: 20}
|
//// user -> User{Name: "noexisting_user", Age: 20}
|
||||||
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 20}).FirstOrInit(&user)
|
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 20}).FirstOrInit(&user)
|
||||||
//// user -> select * from users where name = 'jinzhu';
|
//// user -> select * from users where name = 'jinzhu';
|
||||||
|
@ -127,6 +131,8 @@ db.Where(User{Name: "noexisting_user"}).Attrs(User{Age: 20}).FirstOrCreate(&user
|
||||||
//// user -> select * from users where name = 'noexisting_user';
|
//// user -> select * from users where name = 'noexisting_user';
|
||||||
//// If not record found, will assing the attrs to the user first, then create it
|
//// If not record found, will assing the attrs to the user first, then create it
|
||||||
//// Same as db.Where(User{Name: "noexisting_user"}).FirstOrCreate(&user).Update("age": 20), but one less sql
|
//// Same as db.Where(User{Name: "noexisting_user"}).FirstOrCreate(&user).Update("age": 20), but one less sql
|
||||||
|
db.Where(User{Name: "noexisting_user"}).Attrs("age", 20).FirstOrCreate(&user)
|
||||||
|
// Save as above
|
||||||
//// user -> User{Id: 112, Name: "noexisting_user", Age: 20}
|
//// user -> User{Id: 112, Name: "noexisting_user", Age: 20}
|
||||||
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
|
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
|
||||||
//// user -> select * from users where name = 'jinzhu';
|
//// user -> select * from users where name = 'jinzhu';
|
||||||
|
|
12
chain.go
12
chain.go
|
@ -153,8 +153,8 @@ func (s *Chain) Delete(value interface{}) *Chain {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Chain) Update(column string, value interface{}) *Chain {
|
func (s *Chain) Update(attrs ...interface{}) *Chain {
|
||||||
return s.Updates(map[string]interface{}{column: value}, true)
|
return s.Updates(toSearchableMap(attrs...), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Chain) Updates(values interface{}, ignore_protected_attrs ...bool) *Chain {
|
func (s *Chain) Updates(values interface{}, ignore_protected_attrs ...bool) *Chain {
|
||||||
|
@ -174,13 +174,13 @@ func (s *Chain) First(out interface{}, where ...interface{}) *Chain {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Chain) Attrs(attrs interface{}) *Chain {
|
func (s *Chain) Attrs(attrs ...interface{}) *Chain {
|
||||||
s.initAttrs = append(s.initAttrs, attrs)
|
s.initAttrs = append(s.initAttrs, toSearchableMap(attrs...))
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Chain) Assign(attrs interface{}) *Chain {
|
func (s *Chain) Assign(attrs ...interface{}) *Chain {
|
||||||
s.assignAttrs = append(s.assignAttrs, attrs)
|
s.assignAttrs = append(s.assignAttrs, toSearchableMap(attrs...))
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
do.go
20
do.go
|
@ -133,10 +133,7 @@ func (s *Do) create() {
|
||||||
|
|
||||||
if !s.hasError() {
|
if !s.hasError() {
|
||||||
result := reflect.ValueOf(s.value).Elem()
|
result := reflect.ValueOf(s.value).Elem()
|
||||||
primary_key := result.FieldByName(s.model.primaryKey())
|
setFieldValue(result.FieldByName(s.model.primaryKey()), id)
|
||||||
if primary_key.IsValid() {
|
|
||||||
primary_key.SetInt(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.err(s.model.callMethod("AfterCreate"))
|
s.err(s.model.callMethod("AfterCreate"))
|
||||||
s.err(s.model.callMethod("AfterSave"))
|
s.err(s.model.callMethod("AfterSave"))
|
||||||
|
@ -323,7 +320,7 @@ func (s *Do) count(value interface{}) {
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var dest int64
|
var dest int64
|
||||||
if s.err(rows.Scan(&dest)) == nil {
|
if s.err(rows.Scan(&dest)) == nil {
|
||||||
dest_out.SetInt(dest)
|
setFieldValue(dest_out, dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -523,17 +520,24 @@ func (s *Do) initializeWithSearchCondition() {
|
||||||
for _, clause := range s.whereClause {
|
for _, clause := range s.whereClause {
|
||||||
query := clause["query"]
|
query := clause["query"]
|
||||||
switch query.(type) {
|
switch query.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
for key, value := range query.(map[string]interface{}) {
|
||||||
|
m.setValueByColumn(key, value, s.value)
|
||||||
|
}
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
for _, obj := range query.([]interface{}) {
|
for _, obj := range query.([]interface{}) {
|
||||||
|
switch reflect.ValueOf(obj).Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
m := &Model{data: obj, driver: s.driver}
|
m := &Model{data: obj, driver: s.driver}
|
||||||
for _, field := range m.columnsHasValue("") {
|
for _, field := range m.columnsHasValue("") {
|
||||||
m.setValueByColumn(field.DbName, field.Value, s.value)
|
m.setValueByColumn(field.DbName, field.Value, s.value)
|
||||||
}
|
}
|
||||||
}
|
case reflect.Map:
|
||||||
case map[string]interface{}:
|
for key, value := range obj.(map[string]interface{}) {
|
||||||
for key, value := range query.(map[string]interface{}) {
|
|
||||||
m.setValueByColumn(key, value, s.value)
|
m.setValueByColumn(key, value, s.value)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case interface{}:
|
case interface{}:
|
||||||
m := &Model{data: query, driver: s.driver}
|
m := &Model{data: query, driver: s.driver}
|
||||||
for _, field := range m.columnsHasValue("") {
|
for _, field := range m.columnsHasValue("") {
|
||||||
|
|
|
@ -870,14 +870,14 @@ func TestFindOrInitialize(t *testing.T) {
|
||||||
t.Errorf("user should be initialized with search value and attrs")
|
t.Errorf("user should be initialized with search value and attrs")
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Where(&User{Name: "find or init"}).Assign(User{Age: 44}).FirstOrInit(&user4)
|
db.Where(&User{Name: "find or init"}).Assign("age", 44).FirstOrInit(&user4)
|
||||||
if user4.Name != "find or init" || user4.Id != 0 || user4.Age != 44 {
|
if user4.Name != "find or init" || user4.Id != 0 || user4.Age != 44 {
|
||||||
t.Errorf("user should be initialized with search value and assigned attrs")
|
t.Errorf("user should be initialized with search value and assigned attrs")
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Save(&User{Name: "find or init", Age: 33})
|
db.Save(&User{Name: "find or init", Age: 33})
|
||||||
|
|
||||||
db.Where(&User{Name: "find or init"}).Attrs(User{Age: 44}).FirstOrInit(&user5)
|
db.Where(&User{Name: "find or init"}).Attrs("age", 44).FirstOrInit(&user5)
|
||||||
if user5.Name != "find or init" || user5.Id == 0 || user5.Age != 33 {
|
if user5.Name != "find or init" || user5.Id == 0 || user5.Age != 33 {
|
||||||
t.Errorf("user should be found and not initialized by Attrs")
|
t.Errorf("user should be found and not initialized by Attrs")
|
||||||
}
|
}
|
||||||
|
@ -910,7 +910,7 @@ func TestFindOrCreate(t *testing.T) {
|
||||||
t.Errorf("user should be created with inline search value")
|
t.Errorf("user should be created with inline search value")
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Where(&User{Name: "find or create 3"}).Attrs(User{Age: 44}).FirstOrCreate(&user4)
|
db.Where(&User{Name: "find or create 3"}).Attrs("age", 44).FirstOrCreate(&user4)
|
||||||
if user4.Name != "find or create 3" || user4.Id == 0 || user4.Age != 44 {
|
if user4.Name != "find or create 3" || user4.Id == 0 || user4.Age != 44 {
|
||||||
t.Errorf("user should be created with search value and attrs")
|
t.Errorf("user should be created with search value and attrs")
|
||||||
}
|
}
|
||||||
|
@ -920,7 +920,7 @@ func TestFindOrCreate(t *testing.T) {
|
||||||
t.Errorf("user should be created with search value and assigned attrs")
|
t.Errorf("user should be created with search value and assigned attrs")
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Where(&User{Name: "find or create"}).Attrs(User{Age: 44}).FirstOrInit(&user5)
|
db.Where(&User{Name: "find or create"}).Attrs("age", 44).FirstOrInit(&user5)
|
||||||
if user5.Name != "find or create" || user5.Id == 0 || user5.Age != 33 {
|
if user5.Name != "find or create" || user5.Id == 0 || user5.Age != 33 {
|
||||||
t.Errorf("user should be found and not initialized by Attrs")
|
t.Errorf("user should be found and not initialized by Attrs")
|
||||||
}
|
}
|
||||||
|
|
8
main.go
8
main.go
|
@ -30,12 +30,12 @@ func (s *DB) First(out interface{}, where ...interface{}) *Chain {
|
||||||
return s.buildChain().First(out, where...)
|
return s.buildChain().First(out, where...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DB) Attrs(attrs interface{}) *Chain {
|
func (s *DB) Attrs(attrs ...interface{}) *Chain {
|
||||||
return s.buildChain().Attrs(attrs)
|
return s.buildChain().Attrs(attrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DB) Assign(attrs interface{}) *Chain {
|
func (s *DB) Assign(attrs ...interface{}) *Chain {
|
||||||
return s.buildChain().Assign(attrs)
|
return s.buildChain().Assign(attrs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DB) FirstOrInit(out interface{}, where ...interface{}) *Chain {
|
func (s *DB) FirstOrInit(out interface{}, where ...interface{}) *Chain {
|
||||||
|
|
14
model.go
14
model.go
|
@ -151,9 +151,8 @@ func (m *Model) updatedColumnsAndValues(values map[string]interface{}) (map[stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field := data.FieldByName("UpdatedAt")
|
if values["updated_at"] != nil && len(results) > 0 {
|
||||||
if field.IsValid() && values["updated_at"] != nil && len(results) > 0 {
|
setFieldValue(data.FieldByName("UpdatedAt"), time.Now())
|
||||||
data.FieldByName("UpdatedAt").Set(reflect.ValueOf(time.Now()))
|
|
||||||
}
|
}
|
||||||
result := len(results) > 0
|
result := len(results) > 0
|
||||||
return map[string]interface{}{}, result
|
return map[string]interface{}{}, result
|
||||||
|
@ -238,9 +237,16 @@ func (m *Model) missingColumns() (results []string) {
|
||||||
|
|
||||||
func (m *Model) setValueByColumn(name string, value interface{}, out interface{}) {
|
func (m *Model) setValueByColumn(name string, value interface{}, out interface{}) {
|
||||||
data := reflect.Indirect(reflect.ValueOf(out))
|
data := reflect.Indirect(reflect.ValueOf(out))
|
||||||
|
setFieldValue(data.FieldByName(snakeToUpperCamel(name)), value)
|
||||||
|
}
|
||||||
|
|
||||||
field := data.FieldByName(snakeToUpperCamel(name))
|
func setFieldValue(field reflect.Value, value interface{}) {
|
||||||
if field.IsValid() {
|
if field.IsValid() {
|
||||||
|
switch field.Kind() {
|
||||||
|
case reflect.Int, reflect.Int32, reflect.Int64:
|
||||||
|
field.SetInt(reflect.ValueOf(value).Int())
|
||||||
|
default:
|
||||||
field.Set(reflect.ValueOf(value))
|
field.Set(reflect.ValueOf(value))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
17
utils.go
17
utils.go
|
@ -29,6 +29,23 @@ func snakeToUpperCamel(s string) string {
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toSearchableMap(attrs ...interface{}) (result interface{}) {
|
||||||
|
if len(attrs) > 1 {
|
||||||
|
if str, ok := attrs[0].(string); ok {
|
||||||
|
result = map[string]interface{}{str: attrs[1]}
|
||||||
|
}
|
||||||
|
} else if len(attrs) == 1 {
|
||||||
|
if attr, ok := attrs[0].(map[string]interface{}); ok {
|
||||||
|
result = attr
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr, ok := attrs[0].(interface{}); ok {
|
||||||
|
result = attr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func debug(value interface{}) {
|
func debug(value interface{}) {
|
||||||
fmt.Printf("***************\n")
|
fmt.Printf("***************\n")
|
||||||
fmt.Printf("%+v\n\n", value)
|
fmt.Printf("%+v\n\n", value)
|
||||||
|
|
Loading…
Reference in New Issue