From 65785db65980370e3bffd3ab6d2e1d2160f08e3b Mon Sep 17 00:00:00 2001 From: John Guo Date: Sun, 27 Dec 2020 00:11:26 +0800 Subject: [PATCH] improve Model.Data for shallow value copy for value type of map/slice --- database/gdb/gdb_model_insert.go | 13 +++-- database/gdb/gdb_z_init_test.go | 2 +- database/gdb/gdb_z_mysql_model_test.go | 74 +++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/database/gdb/gdb_model_insert.go b/database/gdb/gdb_model_insert.go index 064cb0d63..41562e665 100644 --- a/database/gdb/gdb_model_insert.go +++ b/database/gdb/gdb_model_insert.go @@ -25,6 +25,8 @@ func (m *Model) Batch(batch int) *Model { // Data sets the operation data for the model. // The parameter can be type of string/map/gmap/slice/struct/*struct, etc. +// Note that, it uses shallow value copying for `data` if `data` is type of map/slice +// to avoid changing it inside function. // Eg: // Data("uid=10000") // Data("uid", 10000) @@ -34,8 +36,7 @@ func (m *Model) Batch(batch int) *Model { func (m *Model) Data(data ...interface{}) *Model { model := m.getModel() if len(data) > 1 { - s := gconv.String(data[0]) - if gstr.Contains(s, "?") { + if s := gconv.String(data[0]); gstr.Contains(s, "?") { model.data = s model.extraArgs = data[1:] } else { @@ -52,9 +53,13 @@ func (m *Model) Data(data ...interface{}) *Model { case Record: model.data = params.Map() case List: - model.data = params + list := make(List, len(params)) + for k, v := range params { + list[k] = gutil.MapCopy(v) + } + model.data = list case Map: - model.data = params + model.data = gutil.MapCopy(params) default: var ( rv = reflect.ValueOf(params) diff --git a/database/gdb/gdb_z_init_test.go b/database/gdb/gdb_z_init_test.go index 681be6bb3..b95081a8b 100644 --- a/database/gdb/gdb_z_init_test.go +++ b/database/gdb/gdb_z_init_test.go @@ -114,7 +114,7 @@ func createTableWithDb(db gdb.DB, table ...string) (name string) { case "sqlite": if _, err := db.Exec(fmt.Sprintf(` CREATE TABLE %s ( - id bigint NOT NULL, + id bigint unsigned NOT NULL AUTO_INCREMENT, passport varchar(45), password char(32) NOT NULL, nickname varchar(45) NOT NULL, diff --git a/database/gdb/gdb_z_mysql_model_test.go b/database/gdb/gdb_z_mysql_model_test.go index af624edc2..6e24164bd 100644 --- a/database/gdb/gdb_z_mysql_model_test.go +++ b/database/gdb/gdb_z_mysql_model_test.go @@ -99,6 +99,60 @@ func Test_Model_Insert(t *testing.T) { }) } +// Using filter dose not affect the outside value inside function. +func Test_Model_Insert_Filter(t *testing.T) { + // map + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + data := g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": gtime.Now().String(), + } + result, err := db.Table(table).Filter().Data(data).Insert() + t.Assert(err, nil) + n, _ := result.LastInsertId() + t.Assert(n, 1) + + t.Assert(data["uid"], 1) + }) + // slice + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + data := g.List{ + g.Map{ + "id": 1, + "uid": 1, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": gtime.Now().String(), + }, + g.Map{ + "id": 2, + "uid": 2, + "passport": "t1", + "password": "25d55ad283aa400af464c76d713c07ad", + "nickname": "name_1", + "create_time": gtime.Now().String(), + }, + } + + result, err := db.Table(table).Filter().Data(data).Insert() + t.Assert(err, nil) + n, _ := result.LastInsertId() + t.Assert(n, 2) + + t.Assert(data[0]["uid"], 1) + t.Assert(data[1]["uid"], 2) + }) +} + // Fix issue: https://github.com/gogf/gf/issues/819 func Test_Model_Insert_WithStructAndSliceAttribute(t *testing.T) { table := createTable() @@ -285,7 +339,7 @@ func Test_Model_InsertIgnore(t *testing.T) { } func Test_Model_Batch(t *testing.T) { - // bacth insert + // batch insert gtest.C(t, func(t *gtest.T) { table := createTable() defer dropTable(table) @@ -314,6 +368,24 @@ func Test_Model_Batch(t *testing.T) { t.Assert(n, 2) }) + // batch insert, retrieving last insert auto-increment id. + gtest.C(t, func(t *gtest.T) { + table := createTable() + defer dropTable(table) + result, err := db.Table(table).Data(g.List{ + {"passport": "t1"}, + {"passport": "t2"}, + {"passport": "t3"}, + {"passport": "t4"}, + {"passport": "t5"}, + }).Batch(2).Insert() + if err != nil { + gtest.Error(err) + } + n, _ := result.RowsAffected() + t.Assert(n, 5) + }) + // batch save gtest.C(t, func(t *gtest.T) { table := createInitTable()