diff --git a/contrib/drivers/mysql/mysql_basic_test.go b/contrib/drivers/mysql/mysql_basic_test.go index bde0c7ac2..8e50f7c47 100644 --- a/contrib/drivers/mysql/mysql_basic_test.go +++ b/contrib/drivers/mysql/mysql_basic_test.go @@ -37,10 +37,10 @@ func Test_Func_ConvertDataForRecord(t *testing.T) { } gtest.C(t, func(t *gtest.T) { c := &gdb.Core{} - m := c.ConvertDataForRecord(nil, new(Test)) + m, err := c.ConvertDataForRecord(nil, new(Test)) + t.AssertNil(err) t.Assert(len(m), 1) - t.AssertNE(m["reset_password_token_at"], nil) - t.Assert(m["reset_password_token_at"], new(mysql.NullTime)) + t.Assert(m["reset_password_token_at"], nil) }) } diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go index 334a7bcd3..721f354d1 100644 --- a/database/gdb/gdb.go +++ b/database/gdb/gdb.go @@ -170,7 +170,7 @@ type DB interface { GetChars() (charLeft string, charRight string) // See Core.GetChars. Tables(ctx context.Context, schema ...string) (tables []string, err error) // See Core.Tables. TableFields(ctx context.Context, table string, schema ...string) (map[string]*TableField, error) // See Core.TableFields. - ConvertDataForRecord(ctx context.Context, data interface{}) map[string]interface{} // See Core.ConvertDataForRecord + ConvertDataForRecord(ctx context.Context, data interface{}) (map[string]interface{}, error) // See Core.ConvertDataForRecord FilteredLink() string // FilteredLink is used for filtering sensitive information in `Link` configuration before output it to tracing server. } diff --git a/database/gdb/gdb_core.go b/database/gdb/gdb_core.go index 5ec62343c..ea468e5d5 100644 --- a/database/gdb/gdb_core.go +++ b/database/gdb/gdb_core.go @@ -552,7 +552,7 @@ func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data inter case reflect.Map, reflect.Struct: var ( fields []string - dataMap = c.db.ConvertDataForRecord(ctx, data) + dataMap map[string]interface{} counterHandler = func(column string, counter Counter) { if counter.Value != 0 { column = c.QuoteWord(column) @@ -570,7 +570,10 @@ func (c *Core) DoUpdate(ctx context.Context, link Link, table string, data inter } } ) - + dataMap, err = c.db.ConvertDataForRecord(ctx, data) + if err != nil { + return nil, err + } for k, v := range dataMap { switch value := v.(type) { case *Counter: diff --git a/database/gdb/gdb_core_structure.go b/database/gdb/gdb_core_structure.go index f7601ec94..bf80272e4 100644 --- a/database/gdb/gdb_core_structure.go +++ b/database/gdb/gdb_core_structure.go @@ -14,6 +14,7 @@ import ( "time" "github.com/gogf/gf/v2/encoding/gbinary" + "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/internal/json" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/text/gregex" @@ -27,27 +28,33 @@ import ( // // The parameter `value` should be type of *map/map/*struct/struct. // It supports embedded struct definition for struct. -func (c *Core) ConvertDataForRecord(ctx context.Context, value interface{}) map[string]interface{} { - var data = DataToMapDeep(value) +func (c *Core) ConvertDataForRecord(ctx context.Context, value interface{}) (map[string]interface{}, error) { + var ( + err error + data = DataToMapDeep(value) + ) for k, v := range data { - data[k] = c.ConvertDataForRecordValue(ctx, v) + data[k], err = c.ConvertDataForRecordValue(ctx, v) + if err != nil { + return nil, gerror.Wrapf(err, `ConvertDataForRecordValue failed for value: %#v`, v) + } } - return data + return data, nil } -func (c *Core) ConvertDataForRecordValue(ctx context.Context, value interface{}) interface{} { +func (c *Core) ConvertDataForRecordValue(ctx context.Context, value interface{}) (interface{}, error) { var ( err error - convertedValue interface{} + convertedValue = value ) // If `value` implements interface `driver.Valuer`, it then uses the interface for value converting. if valuer, ok := value.(driver.Valuer); ok { if convertedValue, err = valuer.Value(); err != nil { if err != nil { - return nil + return nil, err } } - return convertedValue + return convertedValue, nil } // Default value converting. var ( @@ -63,7 +70,10 @@ func (c *Core) ConvertDataForRecordValue(ctx context.Context, value interface{}) // It should ignore the bytes type. if _, ok := value.([]byte); !ok { // Convert the value to JSON. - convertedValue, _ = json.Marshal(value) + convertedValue, err = json.Marshal(value) + if err != nil { + return nil, err + } } case reflect.Struct: @@ -97,11 +107,14 @@ func (c *Core) ConvertDataForRecordValue(ctx context.Context, value interface{}) convertedValue = s.String() } else { // Convert the value to JSON. - convertedValue, _ = json.Marshal(value) + convertedValue, err = json.Marshal(value) + if err != nil { + return nil, err + } } } } - return convertedValue + return convertedValue, nil } // convertFieldValueToLocalValue automatically checks and converts field value from database type diff --git a/database/gdb/gdb_model_insert.go b/database/gdb/gdb_model_insert.go index 2a6a460ee..950758a67 100644 --- a/database/gdb/gdb_model_insert.go +++ b/database/gdb/gdb_model_insert.go @@ -40,6 +40,7 @@ func (m *Model) Batch(batch int) *Model { // Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"}). func (m *Model) Data(data ...interface{}) *Model { var ( + err error ctx = m.GetCtx() model = m.getModel() ) @@ -87,7 +88,10 @@ func (m *Model) Data(data ...interface{}) *Model { } list := make(List, reflectInfo.OriginValue.Len()) for i := 0; i < reflectInfo.OriginValue.Len(); i++ { - list[i] = m.db.ConvertDataForRecord(ctx, reflectInfo.OriginValue.Index(i).Interface()) + list[i], err = m.db.ConvertDataForRecord(ctx, reflectInfo.OriginValue.Index(i).Interface()) + if err != nil { + panic(err) + } } model.data = list @@ -104,15 +108,24 @@ func (m *Model) Data(data ...interface{}) *Model { list = make(List, len(array)) ) for i := 0; i < len(array); i++ { - list[i] = m.db.ConvertDataForRecord(ctx, array[i]) + list[i], err = m.db.ConvertDataForRecord(ctx, array[i]) + if err != nil { + panic(err) + } } model.data = list } else { - model.data = m.db.ConvertDataForRecord(ctx, data[0]) + model.data, err = m.db.ConvertDataForRecord(ctx, data[0]) + if err != nil { + panic(err) + } } case reflect.Map: - model.data = m.db.ConvertDataForRecord(ctx, data[0]) + model.data, err = m.db.ConvertDataForRecord(ctx, data[0]) + if err != nil { + panic(err) + } default: model.data = data[0] @@ -255,11 +268,18 @@ func (m *Model) doInsertWithOption(ctx context.Context, insertOption int) (resul case List: list = value for i, v := range list { - list[i] = m.db.ConvertDataForRecord(ctx, v) + list[i], err = m.db.ConvertDataForRecord(ctx, v) + if err != nil { + return nil, err + } } case Map: - list = List{m.db.ConvertDataForRecord(ctx, value)} + var listItem map[string]interface{} + if listItem, err = m.db.ConvertDataForRecord(ctx, value); err != nil { + return nil, err + } + list = List{listItem} default: reflectInfo := reflection.OriginValueAndKind(newData) @@ -268,21 +288,32 @@ func (m *Model) doInsertWithOption(ctx context.Context, insertOption int) (resul case reflect.Slice, reflect.Array: list = make(List, reflectInfo.OriginValue.Len()) for i := 0; i < reflectInfo.OriginValue.Len(); i++ { - list[i] = m.db.ConvertDataForRecord(ctx, reflectInfo.OriginValue.Index(i).Interface()) + list[i], err = m.db.ConvertDataForRecord(ctx, reflectInfo.OriginValue.Index(i).Interface()) } case reflect.Map: - list = List{m.db.ConvertDataForRecord(ctx, value)} + var listItem map[string]interface{} + if listItem, err = m.db.ConvertDataForRecord(ctx, value); err != nil { + return nil, err + } + list = List{listItem} case reflect.Struct: if v, ok := value.(iInterfaces); ok { array := v.Interfaces() list = make(List, len(array)) for i := 0; i < len(array); i++ { - list[i] = m.db.ConvertDataForRecord(ctx, array[i]) + list[i], err = m.db.ConvertDataForRecord(ctx, array[i]) + if err != nil { + return nil, err + } } } else { - list = List{m.db.ConvertDataForRecord(ctx, value)} + var listItem map[string]interface{} + if listItem, err = m.db.ConvertDataForRecord(ctx, value); err != nil { + return nil, err + } + list = List{listItem} } default: diff --git a/database/gdb/gdb_model_update.go b/database/gdb/gdb_model_update.go index 1a94d81ce..59fb7a3cb 100644 --- a/database/gdb/gdb_model_update.go +++ b/database/gdb/gdb_model_update.go @@ -51,7 +51,11 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro ) switch reflectInfo.OriginKind { case reflect.Map, reflect.Struct: - dataMap := m.db.ConvertDataForRecord(ctx, m.data) + var dataMap map[string]interface{} + dataMap, err = m.db.ConvertDataForRecord(ctx, m.data) + if err != nil { + return nil, err + } // Automatically update the record updating time. if !m.unscoped && fieldNameUpdate != "" { dataMap[fieldNameUpdate] = gtime.Now().String()