mirror of https://github.com/go-gorm/gorm.git
Add Method UpdateColumn, UpdateColumns
This commit is contained in:
parent
5411291173
commit
1a2eef181a
19
README.md
19
README.md
|
@ -320,7 +320,7 @@ db.Where("role = ?", "admin").Or("role = ?", "super_admin").Not("name = ?", "jin
|
|||
user.Name = "jinzhu 2"
|
||||
user.Age = 100
|
||||
db.Save(&user)
|
||||
//// UPDATE users SET name='jinzhu 2', age=100 WHERE id=111;
|
||||
//// UPDATE users SET name='jinzhu 2', age=100, updated_at = '2013-11-17 21:34:10' WHERE id=111;
|
||||
```
|
||||
|
||||
### Update one attribute with `Update`
|
||||
|
@ -328,12 +328,12 @@ db.Save(&user)
|
|||
```go
|
||||
// Update existing user's name if it is changed
|
||||
db.Model(&user).Update("name", "hello")
|
||||
//// UPDATE users SET name='hello' WHERE id=111;
|
||||
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;
|
||||
|
||||
// Find out a user, and update the name if it is changed
|
||||
db.First(&user, 111).Update("name", "hello")
|
||||
//// SELECT * FROM users LIMIT 1;
|
||||
//// UPDATE users SET name='hello' WHERE id=111;
|
||||
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;
|
||||
|
||||
// Update name with search condiation and specified table name
|
||||
db.Table("users").Where(10).Update("name", "hello")
|
||||
|
@ -345,7 +345,7 @@ db.Table("users").Where(10).Update("name", "hello")
|
|||
```go
|
||||
// Update user's name and age if they are changed
|
||||
db.Model(&user).Updates(User{Name: "hello", Age: 18})
|
||||
//// UPDATE users SET name='hello', age=18 WHERE id = 111;
|
||||
//// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
|
||||
|
||||
// Updates with Map
|
||||
db.Table("users").Where(10).Updates(map[string]interface{}{"name": "hello", "age": 18})
|
||||
|
@ -356,6 +356,16 @@ db.Model(User{}).Updates(User{Name: "hello", Age: 18})
|
|||
//// UPDATE users SET name='hello', age=18;
|
||||
```
|
||||
|
||||
### Update attributes without callbacks
|
||||
|
||||
```go
|
||||
db.Model(&user).UpdateColumn("name", "hello")
|
||||
//// UPDATE users SET name='hello' WHERE id = 111;
|
||||
|
||||
db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
|
||||
//// UPDATE users SET name='hello', age=18 WHERE id = 111;
|
||||
```
|
||||
|
||||
## Delete
|
||||
|
||||
### Delete an existing struct
|
||||
|
@ -780,7 +790,6 @@ db.Where("email = ?", "x@example.org").Attrs(User{RegisteredIp: "111.111.111.111
|
|||
```
|
||||
|
||||
## TODO
|
||||
* UpdateColumn/Columns
|
||||
* Scopes
|
||||
* Joins
|
||||
* Scan
|
||||
|
|
55
do.go
55
do.go
|
@ -199,43 +199,52 @@ func (s *Do) create() (i interface{}) {
|
|||
return
|
||||
}
|
||||
|
||||
func (s *Do) convertToMapInterface(values interface{}) map[string]interface{} {
|
||||
attrs := map[string]interface{}{}
|
||||
|
||||
switch value := values.(type) {
|
||||
case map[string]interface{}:
|
||||
attrs = value
|
||||
case []interface{}:
|
||||
for _, v := range value {
|
||||
for key, value := range s.convertToMapInterface(v) {
|
||||
attrs[key] = value
|
||||
}
|
||||
}
|
||||
case interface{}:
|
||||
m := &Model{data: values, do: s}
|
||||
for _, field := range m.columnsHasValue("other") {
|
||||
attrs[field.dbName] = field.Value
|
||||
}
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
|
||||
func (s *Do) updateAttrs(values interface{}, ignore_protected_attrs ...bool) *Do {
|
||||
ignore_protected := len(ignore_protected_attrs) > 0 && ignore_protected_attrs[0]
|
||||
s.usingUpdate = true
|
||||
|
||||
switch value := values.(type) {
|
||||
case map[string]interface{}:
|
||||
if len(value) > 0 {
|
||||
results, has_update := s.model.updatedColumnsAndValues(value, ignore_protected)
|
||||
if maps := s.convertToMapInterface(values); len(maps) > 0 {
|
||||
results, has_update := s.model.updatedColumnsAndValues(maps, ignore_protected)
|
||||
if len(results) > 0 {
|
||||
s.update_attrs = results
|
||||
}
|
||||
s.hasUpdate = has_update
|
||||
}
|
||||
case []interface{}:
|
||||
for _, v := range value {
|
||||
s.updateAttrs(v)
|
||||
}
|
||||
case interface{}:
|
||||
m := &Model{data: values, do: s}
|
||||
attrs := map[string]interface{}{}
|
||||
for _, field := range m.columnsHasValue("other") {
|
||||
attrs[field.dbName] = field.Value
|
||||
}
|
||||
s.updateAttrs(attrs)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Do) prepareUpdateSql() {
|
||||
func (s *Do) prepareUpdateSql(include_self bool) {
|
||||
var sqls []string
|
||||
for key, value := range s.update_attrs {
|
||||
sqls = append(sqls, fmt.Sprintf("%v = %v", key, s.addToVars(value)))
|
||||
}
|
||||
|
||||
if include_self {
|
||||
for key, value := range s.model.columnsAndValues("update") {
|
||||
sqls = append(sqls, fmt.Sprintf("%v = %v", key, s.addToVars(value)))
|
||||
}
|
||||
}
|
||||
|
||||
s.sql = fmt.Sprintf(
|
||||
"UPDATE %v SET %v %v",
|
||||
|
@ -246,6 +255,16 @@ func (s *Do) prepareUpdateSql() {
|
|||
return
|
||||
}
|
||||
|
||||
func (s *Do) updateColumns(value interface{}) *Do {
|
||||
s.update_attrs = s.convertToMapInterface(value)
|
||||
s.prepareUpdateSql(false)
|
||||
if !s.db.hasError() {
|
||||
s.exec()
|
||||
s.updateAttrs(s.update_attrs)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Do) update() *Do {
|
||||
if s.usingUpdate && !s.hasUpdate {
|
||||
return s
|
||||
|
@ -255,7 +274,7 @@ func (s *Do) update() *Do {
|
|||
s.model.callMethod("BeforeSave")
|
||||
s.saveBeforeAssociations()
|
||||
|
||||
s.prepareUpdateSql()
|
||||
s.prepareUpdateSql(true)
|
||||
|
||||
if !s.db.hasError() {
|
||||
s.exec()
|
||||
|
|
27
gorm_test.go
27
gorm_test.go
|
@ -900,6 +900,31 @@ func TestUpdates(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestUpdateColumn(t *testing.T) {
|
||||
product1 := Product{Code: "update_column 1", Price: 10}
|
||||
product2 := Product{Code: "update_column 2", Price: 20}
|
||||
db.Save(&product1).Save(&product2).UpdateColumn(map[string]interface{}{"code": "update_column 3", "price": 100})
|
||||
if product2.Code != "update_column 3" || product2.Price != 100 {
|
||||
t.Errorf("product 2 should be updated with update column")
|
||||
}
|
||||
|
||||
var product3 Product
|
||||
db.First(&product3, product1.Id)
|
||||
if product3.Code != "update_column 1" || product3.Price != 10 {
|
||||
t.Errorf("product 1 should not be updated")
|
||||
}
|
||||
|
||||
var product4, product5 Product
|
||||
db.First(&product4, product2.Id)
|
||||
updated_at1 := product4.UpdatedAt
|
||||
|
||||
db.Model(Product{}).Where(product2.Id).UpdateColumn("code", "update_column_new")
|
||||
db.First(&product5, product2.Id)
|
||||
if updated_at1.Format(time.RFC3339Nano) != product5.UpdatedAt.Format(time.RFC3339Nano) {
|
||||
t.Errorf("updated_at should not be updated with update column")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSoftDelete(t *testing.T) {
|
||||
type Order struct {
|
||||
Id int64
|
||||
|
@ -1444,7 +1469,7 @@ func BenchmarkGorm(b *testing.B) {
|
|||
// Query
|
||||
db.First(&BigEmail{}, "email = ?", e)
|
||||
// Update
|
||||
db.Model(&email).Update("email", "new-"+e)
|
||||
db.Model(&email).UpdateColumn("email", "new-"+e)
|
||||
// Delete
|
||||
db.Delete(&email)
|
||||
}
|
||||
|
|
8
main.go
8
main.go
|
@ -153,6 +153,14 @@ func (s *DB) Updates(values interface{}, ignore_protected_attrs ...bool) *DB {
|
|||
return s.clone().do(s.data).begin().updateAttrs(values, ignore_protected_attrs...).update().commit_or_rollback().db
|
||||
}
|
||||
|
||||
func (s *DB) UpdateColumn(attrs ...interface{}) *DB {
|
||||
return s.UpdateColumns(toSearchableMap(attrs...), true)
|
||||
}
|
||||
|
||||
func (s *DB) UpdateColumns(values interface{}, ignore_protected_attrs ...bool) *DB {
|
||||
return s.clone().do(s.data).begin().updateColumns(values).commit_or_rollback().db
|
||||
}
|
||||
|
||||
func (s *DB) Save(value interface{}) *DB {
|
||||
return s.clone().do(value).begin().save().commit_or_rollback().db
|
||||
}
|
||||
|
|
4
model.go
4
model.go
|
@ -134,6 +134,10 @@ func (m *Model) updatedColumnsAndValues(values map[string]interface{}, ignore_pr
|
|||
}
|
||||
|
||||
data := m.reflectData()
|
||||
if !data.CanAddr() {
|
||||
return
|
||||
}
|
||||
|
||||
for key, value := range values {
|
||||
if field := data.FieldByName(snakeToUpperCamel(key)); field.IsValid() {
|
||||
if field.Interface() != value {
|
||||
|
|
Loading…
Reference in New Issue