Support extra options for inserting, querying, deleting, updating SQL, close #721, #769

This commit is contained in:
Jinzhu 2016-02-15 19:36:48 +08:00
parent f9c6d17b2a
commit c9dfd80959
6 changed files with 72 additions and 12 deletions

View File

@ -259,6 +259,11 @@ db.Create(&user)
//// INSERT INTO "languages" ("name") VALUES ('EN');
//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 2);
//// COMMIT;
// Add extra SQL option for inserting SQL
db.Set("gorm:insert_option", "ON CONFLICT").Create(&product)
// INSERT INTO products (name, code) VALUES ("name", "code") ON CONFLICT;
```
Refer [Associations](#associations) for more details
@ -281,6 +286,10 @@ db.Find(&users)
// Get record with primary key
db.First(&user, 10)
//// SELECT * FROM users WHERE id = 10;
// Add extra SQL option for selecting SQL
db.Set("gorm:query_option", "FOR UPDATE").First(&user, 10)
//// SELECT * FROM users WHERE id = 10 FOR UPDATE;
```
### Query With Where (Plain SQL)
@ -460,6 +469,10 @@ db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "acti
// Update multiple attributes if they are changed (update with struct only works with none zero values)
db.Model(&user).Updates(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
// Add extra SQL option for updating SQL
db.Model(&user).Set("gorm:update_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Update("name, "hello")
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111 OPTION (OPTIMIZE FOR UNKNOWN);
```
### Update Without Callbacks
@ -513,6 +526,10 @@ DB.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("qua
// Delete an existing record
db.Delete(&email)
//// DELETE from emails where id=10;
// Add extra SQL option for deleting SQL
db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email)
//// DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);
```
### Batch Delete

View File

@ -75,8 +75,13 @@ func createCallback(scope *Scope) {
returningColumn = "*"
quotedTableName = scope.QuotedTableName()
primaryField = scope.PrimaryField()
extraOption string
)
if str, ok := scope.Get("gorm:insert_option"); ok {
extraOption = fmt.Sprint(str)
}
if primaryField != nil {
returningColumn = scope.Quote(primaryField.DBName)
}
@ -84,14 +89,20 @@ func createCallback(scope *Scope) {
lastInsertIdReturningSuffix := scope.Dialect().LastInsertIdReturningSuffix(quotedTableName, returningColumn)
if len(columns) == 0 {
scope.Raw(fmt.Sprintf("INSERT INTO %v DEFAULT VALUES %v", quotedTableName, lastInsertIdReturningSuffix))
scope.Raw(fmt.Sprintf(
"INSERT INTO %v DEFAULT VALUES%v%v",
quotedTableName,
addExtraSpaceIfExist(extraOption),
addExtraSpaceIfExist(lastInsertIdReturningSuffix),
))
} else {
scope.Raw(fmt.Sprintf(
"INSERT INTO %v (%v) VALUES (%v) %v",
"INSERT INTO %v (%v) VALUES (%v)%v%v",
scope.QuotedTableName(),
strings.Join(columns, ","),
strings.Join(placeholders, ","),
lastInsertIdReturningSuffix,
addExtraSpaceIfExist(extraOption),
addExtraSpaceIfExist(lastInsertIdReturningSuffix),
))
}

View File

@ -21,15 +21,26 @@ func beforeDeleteCallback(scope *Scope) {
// deleteCallback used to delete data from database or set deleted_at to current time (when using with soft delete)
func deleteCallback(scope *Scope) {
if !scope.HasError() {
var extraOption string
if str, ok := scope.Get("gorm:delete_option"); ok {
extraOption = fmt.Sprint(str)
}
if !scope.Search.Unscoped && scope.HasColumn("DeletedAt") {
scope.Raw(
fmt.Sprintf("UPDATE %v SET deleted_at=%v %v",
scope.Raw(fmt.Sprintf(
"UPDATE %v SET deleted_at=%v%v%v",
scope.QuotedTableName(),
scope.AddToVars(NowFunc()),
scope.CombinedConditionSql(),
addExtraSpaceIfExist(scope.CombinedConditionSql()),
addExtraSpaceIfExist(extraOption),
)).Exec()
} else {
scope.Raw(fmt.Sprintf("DELETE FROM %v %v", scope.QuotedTableName(), scope.CombinedConditionSql())).Exec()
scope.Raw(fmt.Sprintf(
"DELETE FROM %v%v%v",
scope.QuotedTableName(),
addExtraSpaceIfExist(scope.CombinedConditionSql()),
addExtraSpaceIfExist(extraOption),
)).Exec()
}
}
}

View File

@ -51,8 +51,13 @@ func queryCallback(scope *Scope) {
scope.prepareQuerySql()
if !scope.HasError() {
var extraOption string
if str, ok := scope.Get("gorm:query_option"); ok {
extraOption = fmt.Sprint(str)
}
scope.db.RowsAffected = 0
if rows, err := scope.SqlDB().Query(scope.Sql, scope.SqlVars...); scope.Err(err) == nil {
if rows, err := scope.SqlDB().Query(scope.Sql+addExtraSpaceIfExist(extraOption), scope.SqlVars...); scope.Err(err) == nil {
defer rows.Close()
columns, _ := rows.Columns()

View File

@ -90,9 +90,18 @@ func updateCallback(scope *Scope) {
}
}
var extraOption string
if str, ok := scope.Get("gorm:update_option"); ok {
extraOption = fmt.Sprint(str)
}
if len(sqls) > 0 {
scope.Raw(fmt.Sprintf(
"UPDATE %v SET %v %v", scope.QuotedTableName(), strings.Join(sqls, ", "), scope.CombinedConditionSql(),
"UPDATE %v SET %v%v%v",
scope.QuotedTableName(),
strings.Join(sqls, ", "),
addExtraSpaceIfExist(scope.CombinedConditionSql()),
addExtraSpaceIfExist(extraOption),
)).Exec()
}
}

View File

@ -276,3 +276,10 @@ func getValueFromFields(value reflect.Value, fieldNames []string) (results []int
}
return
}
func addExtraSpaceIfExist(str string) string {
if str != "" {
return " " + str
}
return ""
}