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.Name = "jinzhu 2"
|
||||||
user.Age = 100
|
user.Age = 100
|
||||||
db.Save(&user)
|
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`
|
### Update one attribute with `Update`
|
||||||
@ -328,12 +328,12 @@ db.Save(&user)
|
|||||||
```go
|
```go
|
||||||
// Update existing user's name if it is changed
|
// Update existing user's name if it is changed
|
||||||
db.Model(&user).Update("name", "hello")
|
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
|
// Find out a user, and update the name if it is changed
|
||||||
db.First(&user, 111).Update("name", "hello")
|
db.First(&user, 111).Update("name", "hello")
|
||||||
//// SELECT * FROM users LIMIT 1;
|
//// 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
|
// Update name with search condiation and specified table name
|
||||||
db.Table("users").Where(10).Update("name", "hello")
|
db.Table("users").Where(10).Update("name", "hello")
|
||||||
@ -345,7 +345,7 @@ db.Table("users").Where(10).Update("name", "hello")
|
|||||||
```go
|
```go
|
||||||
// Update user's name and age if they are changed
|
// Update user's name and age if they are changed
|
||||||
db.Model(&user).Updates(User{Name: "hello", Age: 18})
|
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
|
// Updates with Map
|
||||||
db.Table("users").Where(10).Updates(map[string]interface{}{"name": "hello", "age": 18})
|
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 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
|
||||||
|
|
||||||
### Delete an existing struct
|
### Delete an existing struct
|
||||||
@ -780,7 +790,6 @@ db.Where("email = ?", "x@example.org").Attrs(User{RegisteredIp: "111.111.111.111
|
|||||||
```
|
```
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
* UpdateColumn/Columns
|
|
||||||
* Scopes
|
* Scopes
|
||||||
* Joins
|
* Joins
|
||||||
* Scan
|
* Scan
|
||||||
|
65
do.go
65
do.go
@ -199,42 +199,51 @@ func (s *Do) create() (i interface{}) {
|
|||||||
return
|
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 {
|
func (s *Do) updateAttrs(values interface{}, ignore_protected_attrs ...bool) *Do {
|
||||||
ignore_protected := len(ignore_protected_attrs) > 0 && ignore_protected_attrs[0]
|
ignore_protected := len(ignore_protected_attrs) > 0 && ignore_protected_attrs[0]
|
||||||
s.usingUpdate = true
|
s.usingUpdate = true
|
||||||
|
|
||||||
switch value := values.(type) {
|
if maps := s.convertToMapInterface(values); len(maps) > 0 {
|
||||||
case map[string]interface{}:
|
results, has_update := s.model.updatedColumnsAndValues(maps, ignore_protected)
|
||||||
if len(value) > 0 {
|
if len(results) > 0 {
|
||||||
results, has_update := s.model.updatedColumnsAndValues(value, ignore_protected)
|
s.update_attrs = results
|
||||||
if len(results) > 0 {
|
|
||||||
s.update_attrs = results
|
|
||||||
}
|
|
||||||
s.hasUpdate = has_update
|
|
||||||
}
|
}
|
||||||
case []interface{}:
|
s.hasUpdate = has_update
|
||||||
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
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Do) prepareUpdateSql() {
|
func (s *Do) prepareUpdateSql(include_self bool) {
|
||||||
var sqls []string
|
var sqls []string
|
||||||
for key, value := range s.update_attrs {
|
for key, value := range s.update_attrs {
|
||||||
sqls = append(sqls, fmt.Sprintf("%v = %v", key, s.addToVars(value)))
|
sqls = append(sqls, fmt.Sprintf("%v = %v", key, s.addToVars(value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
for key, value := range s.model.columnsAndValues("update") {
|
if include_self {
|
||||||
sqls = append(sqls, fmt.Sprintf("%v = %v", key, s.addToVars(value)))
|
for key, value := range s.model.columnsAndValues("update") {
|
||||||
|
sqls = append(sqls, fmt.Sprintf("%v = %v", key, s.addToVars(value)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.sql = fmt.Sprintf(
|
s.sql = fmt.Sprintf(
|
||||||
@ -246,6 +255,16 @@ func (s *Do) prepareUpdateSql() {
|
|||||||
return
|
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 {
|
func (s *Do) update() *Do {
|
||||||
if s.usingUpdate && !s.hasUpdate {
|
if s.usingUpdate && !s.hasUpdate {
|
||||||
return s
|
return s
|
||||||
@ -255,7 +274,7 @@ func (s *Do) update() *Do {
|
|||||||
s.model.callMethod("BeforeSave")
|
s.model.callMethod("BeforeSave")
|
||||||
s.saveBeforeAssociations()
|
s.saveBeforeAssociations()
|
||||||
|
|
||||||
s.prepareUpdateSql()
|
s.prepareUpdateSql(true)
|
||||||
|
|
||||||
if !s.db.hasError() {
|
if !s.db.hasError() {
|
||||||
s.exec()
|
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) {
|
func TestSoftDelete(t *testing.T) {
|
||||||
type Order struct {
|
type Order struct {
|
||||||
Id int64
|
Id int64
|
||||||
@ -1444,7 +1469,7 @@ func BenchmarkGorm(b *testing.B) {
|
|||||||
// Query
|
// Query
|
||||||
db.First(&BigEmail{}, "email = ?", e)
|
db.First(&BigEmail{}, "email = ?", e)
|
||||||
// Update
|
// Update
|
||||||
db.Model(&email).Update("email", "new-"+e)
|
db.Model(&email).UpdateColumn("email", "new-"+e)
|
||||||
// Delete
|
// Delete
|
||||||
db.Delete(&email)
|
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
|
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 {
|
func (s *DB) Save(value interface{}) *DB {
|
||||||
return s.clone().do(value).begin().save().commit_or_rollback().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()
|
data := m.reflectData()
|
||||||
|
if !data.CanAddr() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for key, value := range values {
|
for key, value := range values {
|
||||||
if field := data.FieldByName(snakeToUpperCamel(key)); field.IsValid() {
|
if field := data.FieldByName(snakeToUpperCamel(key)); field.IsValid() {
|
||||||
if field.Interface() != value {
|
if field.Interface() != value {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user