From f4da17914033b71b831da9ef462a47eb70efc060 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 6 Nov 2020 00:00:41 +0800 Subject: [PATCH] there should be WHERE statement in Update/Delete operations --- database/gdb/gdb_model_delete.go | 8 +++++- database/gdb/gdb_model_fields.go | 4 +-- database/gdb/gdb_model_update.go | 7 ++++- database/gdb/gdb_model_utility.go | 28 ++++++++++++++++++++ database/gdb/gdb_z_mysql_method_test.go | 4 +-- database/gdb/gdb_z_mysql_model_test.go | 25 ++++++++++++++--- database/gdb/gdb_z_mysql_transaction_test.go | 4 +-- 7 files changed, 68 insertions(+), 12 deletions(-) diff --git a/database/gdb/gdb_model_delete.go b/database/gdb/gdb_model_delete.go index b9bb9ae88..7c0ea400b 100644 --- a/database/gdb/gdb_model_delete.go +++ b/database/gdb/gdb_model_delete.go @@ -9,7 +9,9 @@ package gdb import ( "database/sql" "fmt" + "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/os/gtime" + "github.com/gogf/gf/text/gstr" ) // Delete does "DELETE FROM ... " statement for the model. @@ -38,5 +40,9 @@ func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) { append([]interface{}{gtime.Now().String()}, conditionArgs...), ) } - return m.db.DoDelete(m.getLink(true), m.tables, conditionWhere+conditionExtra, conditionArgs...) + conditionStr := conditionWhere + conditionExtra + if !gstr.ContainsI(conditionStr, " WHERE ") { + return nil, gerror.New("there should be WHERE condition statement for DELETE operation") + } + return m.db.DoDelete(m.getLink(true), m.tables, conditionStr, conditionArgs...) } diff --git a/database/gdb/gdb_model_fields.go b/database/gdb/gdb_model_fields.go index bccdeb69a..28c317ba3 100644 --- a/database/gdb/gdb_model_fields.go +++ b/database/gdb/gdb_model_fields.go @@ -27,7 +27,7 @@ func (m *Model) Filter() *Model { func (m *Model) Fields(fields ...string) *Model { if len(fields) > 0 { model := m.getModel() - model.fields = gstr.Join(fields, ",") + model.fields = gstr.Join(m.mappingToTableFields(fields), ",") return model } return m @@ -38,7 +38,7 @@ func (m *Model) Fields(fields ...string) *Model { func (m *Model) FieldsEx(fields ...string) *Model { if len(fields) > 0 { model := m.getModel() - model.fieldsEx = gstr.Join(fields, ",") + model.fieldsEx = gstr.Join(m.mappingToTableFields(fields), ",") return model } return m diff --git a/database/gdb/gdb_model_update.go b/database/gdb/gdb_model_update.go index ef1e5099c..32fdebc3a 100644 --- a/database/gdb/gdb_model_update.go +++ b/database/gdb/gdb_model_update.go @@ -10,6 +10,7 @@ import ( "database/sql" "errors" "fmt" + "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/text/gstr" "github.com/gogf/gf/util/gconv" @@ -77,11 +78,15 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro if err != nil { return nil, err } + conditionStr := conditionWhere + conditionExtra + if !gstr.ContainsI(conditionStr, " WHERE ") { + return nil, gerror.New("there should be WHERE condition statement for UPDATE operation") + } return m.db.DoUpdate( m.getLink(true), m.tables, newData, - conditionWhere+conditionExtra, + conditionStr, m.mergeArguments(conditionArgs)..., ) } diff --git a/database/gdb/gdb_model_utility.go b/database/gdb/gdb_model_utility.go index c825671d2..89b02e544 100644 --- a/database/gdb/gdb_model_utility.go +++ b/database/gdb/gdb_model_utility.go @@ -13,6 +13,7 @@ import ( "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/text/gstr" "github.com/gogf/gf/util/gconv" + "github.com/gogf/gf/util/gutil" "time" ) @@ -26,6 +27,33 @@ func (m *Model) getModel() *Model { } } +// mappingToTableFields mappings and changes given field name to really table field name. +func (m *Model) mappingToTableFields(fields []string) []string { + var ( + foundKey = "" + fieldsArray = gstr.SplitAndTrim(gstr.Join(fields, ","), ",") + ) + + if fieldsMap, err := m.db.TableFields(m.tables); err == nil { + fieldsKeyMap := make(map[string]interface{}, len(fieldsMap)) + for k, _ := range fieldsMap { + fieldsKeyMap[k] = nil + } + for i, v := range fieldsArray { + if _, ok := fieldsKeyMap[v]; !ok { + if gstr.Contains(v, " ") || gstr.Contains(v, ".") { + continue + } + foundKey, _ = gutil.MapPossibleItemByKey(fieldsKeyMap, v) + if foundKey != "" { + fieldsArray[i] = foundKey + } + } + } + } + return fieldsArray +} + // filterDataForInsertOrUpdate does filter feature with data for inserting/updating operations. // Note that, it does not filter list item, which is also type of map, for "omit empty" feature. func (m *Model) filterDataForInsertOrUpdate(data interface{}) (interface{}, error) { diff --git a/database/gdb/gdb_z_mysql_method_test.go b/database/gdb/gdb_z_mysql_method_test.go index a74190b37..a0b5f819c 100644 --- a/database/gdb/gdb_z_mysql_method_test.go +++ b/database/gdb/gdb_z_mysql_method_test.go @@ -719,7 +719,7 @@ func Test_DB_Delete(t *testing.T) { table := createInitTable() defer dropTable(table) gtest.C(t, func(t *gtest.T) { - result, err := db.Delete(table, nil) + result, err := db.Delete(table, 1) t.Assert(err, nil) n, _ := result.RowsAffected() t.Assert(n, SIZE) @@ -768,7 +768,7 @@ func Test_DB_Time(t *testing.T) { }) gtest.C(t, func(t *gtest.T) { - result, err := db.Delete(table, nil) + result, err := db.Delete(table, 1) t.Assert(err, nil) n, _ := result.RowsAffected() t.Assert(n, 2) diff --git a/database/gdb/gdb_z_mysql_model_test.go b/database/gdb/gdb_z_mysql_model_test.go index 1535774b3..874c47f1d 100644 --- a/database/gdb/gdb_z_mysql_model_test.go +++ b/database/gdb/gdb_z_mysql_model_test.go @@ -389,7 +389,7 @@ func Test_Model_Update(t *testing.T) { defer dropTable(table) // UPDATE...LIMIT gtest.C(t, func(t *gtest.T) { - result, err := db.Table(table).Data("nickname", "T100").Order("id desc").Limit(2).Update() + result, err := db.Table(table).Data("nickname", "T100").Where(1).Order("id desc").Limit(2).Update() t.Assert(err, nil) n, _ := result.RowsAffected() t.Assert(n, 2) @@ -1769,14 +1769,14 @@ func Test_Model_Delete(t *testing.T) { // DELETE...LIMIT gtest.C(t, func(t *gtest.T) { - result, err := db.Table(table).Limit(2).Delete() + result, err := db.Table(table).Where(1).Limit(2).Delete() t.Assert(err, nil) n, _ := result.RowsAffected() t.Assert(n, 2) }) gtest.C(t, func(t *gtest.T) { - result, err := db.Table(table).Delete() + result, err := db.Table(table).Where(1).Delete() t.Assert(err, nil) n, _ := result.RowsAffected() t.Assert(n, SIZE-2) @@ -2036,7 +2036,7 @@ func Test_Model_Option_Where(t *testing.T) { gtest.C(t, func(t *gtest.T) { table := createInitTable() defer dropTable(table) - r, err := db.Table(table).OmitEmpty().Data("nickname", 1).Where(g.Map{"id": 0, "passport": ""}).Update() + r, err := db.Table(table).OmitEmpty().Data("nickname", 1).Where(g.Map{"id": 0, "passport": ""}).And(1).Update() t.Assert(err, nil) n, _ := r.RowsAffected() t.Assert(n, SIZE) @@ -2601,6 +2601,23 @@ func Test_Model_Min_Max(t *testing.T) { }) } +func Test_Model_Fields_AutoMapping(t *testing.T) { + table := createInitTable() + defer dropTable(table) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Table(table).Fields("ID").Where("id", 2).Value() + t.Assert(err, nil) + t.Assert(value.Int(), 2) + }) + + gtest.C(t, func(t *gtest.T) { + value, err := db.Table(table).Fields("NICK_NAME").Where("id", 2).Value() + t.Assert(err, nil) + t.Assert(value.String(), "name_2") + }) +} + func Test_Model_NullField(t *testing.T) { table := createTable() defer dropTable(table) diff --git a/database/gdb/gdb_z_mysql_transaction_test.go b/database/gdb/gdb_z_mysql_transaction_test.go index b5c54dfdb..967391957 100644 --- a/database/gdb/gdb_z_mysql_transaction_test.go +++ b/database/gdb/gdb_z_mysql_transaction_test.go @@ -676,7 +676,7 @@ func Test_TX_Delete(t *testing.T) { if err != nil { gtest.Error(err) } - if _, err := tx.Delete(table, nil); err != nil { + if _, err := tx.Delete(table, 1); err != nil { gtest.Error(err) } if err := tx.Commit(); err != nil { @@ -696,7 +696,7 @@ func Test_TX_Delete(t *testing.T) { if err != nil { gtest.Error(err) } - if _, err := tx.Delete(table, nil); err != nil { + if _, err := tx.Delete(table, 1); err != nil { gtest.Error(err) } if n, err := tx.Table(table).Count(); err != nil {